DavidBazaldua commited on
Commit
2846513
Β·
verified Β·
1 Parent(s): 7e495a0

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.js +188 -106
  2. index.html +524 -237
app.js CHANGED
@@ -2,64 +2,64 @@
2
  HCP Segmentation Dashboard β€” Chart.js Unified Engine
3
  All data from hcp_analysis_clean.parquet (191 columns)
4
  ============================================================ */
5
- Chart.defaults.color='#64748b';Chart.defaults.borderColor='#e2e8f0';Chart.defaults.font.family="'Inter',sans-serif";Chart.defaults.font.size=13;
6
- Chart.defaults.plugins.legend.labels.usePointStyle=true;Chart.defaults.plugins.legend.labels.pointStyle='circle';Chart.defaults.plugins.legend.labels.padding=20;
7
- Chart.defaults.plugins.tooltip.backgroundColor='#1e293b';Chart.defaults.plugins.tooltip.padding=14;Chart.defaults.plugins.tooltip.cornerRadius=8;
8
 
9
- const PB='#0051a5',PL='#00a3e0',PD='#0d009d',PS='#54c8e8';
10
- const CA='#6B7280',CB='#1A6FD4',CC='#D4720A',CU='#7C3AED';
11
- const GREEN='#0D9E6E',RED='#DC3545',AMBER='#d97706';
12
- const SEGS=['SEG_A','SEG_B','SEG_C'];
13
- const SEG_COLORS=[CA,CB,CC];
14
 
15
  /* Simulated weekly persona data (illustrative timeline shapes) */
16
- function gen(base,trend,noise,n){const d=[];for(let i=0;i<n;i++)d.push(Math.max(0,Math.round((base+trend*i+(Math.random()-0.5)*noise)*10)/10));return d;}
17
- const W=20,wk=Array.from({length:W},(_,i)=>`W${(i+1)*4}`);
18
- const P={a:{trx:gen(12,0,1.5,W),eng:gen(2,0.02,0.5,W),nrx:gen(1,0,0.5,W)},b:{trx:gen(8,0.4,2,W),eng:gen(5,0.3,1,W),nrx:gen(3,0.25,0.8,W)},c:{trx:gen(5,0.15,1.5,W),eng:gen(3,0.1,1.2,W),nrx:gen(2,0.08,0.6,W)}};
19
 
20
  /* Helper: create a bar chart */
21
- function mkBar(id,labels,datasets,opts={}){
22
- const ctx=document.getElementById(id);if(!ctx)return null;
23
- return new Chart(ctx,{type:'bar',data:{labels,datasets},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{display:datasets.length>1,position:'bottom'},...(opts.plugins||{})},scales:{y:{beginAtZero:true,grid:{color:'#f1f5f9'},...(opts.y||{})},x:{grid:{display:false},...(opts.x||{})}},...(opts.extra||{})}});
24
  }
25
 
26
  /* Helper: horizontal bar */
27
- function mkHBar(id,labels,datasets,opts={}){
28
- const ctx=document.getElementById(id);if(!ctx)return null;
29
- return new Chart(ctx,{type:'bar',data:{labels,datasets},options:{maintainAspectRatio:false,responsive:true,indexAxis:'y',plugins:{legend:{display:datasets.length>1,position:'bottom'}},scales:{x:{beginAtZero:true,grid:{color:'#f1f5f9'},...(opts.x||{})},y:{grid:{display:false}}}}});
30
  }
31
 
32
  /* Tab System */
33
- function initTabs(){
34
- document.querySelectorAll('.tab-btn').forEach(btn=>{btn.addEventListener('click',()=>{document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));document.querySelectorAll('.tab-content').forEach(c=>c.classList.remove('active'));btn.classList.add('active');const p=document.getElementById(btn.dataset.tab);if(p){p.classList.add('active');if(!p.dataset.loaded){loadTab(btn.dataset.tab);p.dataset.loaded='1';}}});});
35
- document.querySelectorAll('.sub-tab').forEach(btn=>{btn.addEventListener('click',()=>{const g=btn.closest('.sub-tabs'),ct=btn.closest('.tab-content')||document;g.querySelectorAll('.sub-tab').forEach(b=>b.classList.remove('active'));ct.querySelectorAll('.sub-panel').forEach(p=>p.classList.remove('active'));btn.classList.add('active');const p=ct.querySelector(`#${btn.dataset.subtab}`);if(p)p.classList.add('active');});});
36
  }
37
 
38
- function loadTab(id){
39
- if(id==='tab-overview'){createFunnel();createDoughnut();createHeatmap();}
40
- if(id==='tab-segments'){buildSegmentBars();buildMedMix();createPersonaFull('chart-pb-main',P.b,PL);createPersonaFull('chart-pc-main',P.c,PD);createPersonaFull('chart-pa-main',P.a,PB);}
41
- if(id==='tab-adoption'){buildAdoptionPct();buildAdoptionAbs();buildGrowthSignals();buildTrendBars();}
42
- if(id==='tab-competitive'){buildCompShare();buildCompRatio();buildScatterUC();}
43
- if(id==='tab-engagement'){buildEngagement();buildScatterEng();}
44
- if(id==='tab-opportunity'){buildOpportunityCharts();}
45
- if(id==='tab-specialty'){buildSpecialtyStack();buildSpecialtyPct();}
46
 
47
  }
48
 
49
  /* Counters */
50
- function animateCounters(){document.querySelectorAll('[data-count]').forEach(el=>{const t=parseFloat(el.dataset.count),sf=el.dataset.suffix||'',dur=1200,st=performance.now();(function u(now){const p=Math.min((now-st)/dur,1),v=t*(1-Math.pow(1-p,3));el.textContent=(el.dataset.count.includes('.')?v.toFixed(1):Math.round(v).toLocaleString())+sf;if(p<1)requestAnimationFrame(u);})(st);});}
51
 
52
  /* ==================== TAB 1: OVERVIEW ==================== */
53
- function createFunnel(){mkBar('chart-funnel',['Total Market','Labeled','Unlabeled','SEG_A','SEG_B','SEG_C'],[{data:[20931,11899,9032,6406,3349,2144],backgroundColor:['#e2e8f0','#cbd5e1','#94a3b8',PB,PL,PD],borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
54
 
55
- function createDoughnut(){const ctx=document.getElementById('chart-doughnut');if(!ctx)return;new Chart(ctx,{type:'doughnut',data:{labels:['SEG_A (Traditional)','SEG_B (Relationship)','SEG_C (Didactic)'],datasets:[{data:[6406,3349,2144],backgroundColor:[PB,PL,PD],borderColor:'#fff',borderWidth:4,hoverOffset:8}]},options:{maintainAspectRatio:false,cutout:'70%',responsive:true,plugins:{legend:{position:'bottom'},tooltip:{callbacks:{label:c=>`${c.label}: ${c.raw.toLocaleString()} HCPs (${(c.raw/11899*100).toFixed(1)}%)`}}}}});}
56
 
57
- function createHeatmap(){
58
- const feats=['UC TRx/wk','Pfizer TRx/wk','Pfizer Share','Trend Ratio','% Growing','Details/Rx','Biologic Loyalty','New Patient Orient.'];
59
- const raw=[[0.1713,0.0005,0.0036,0.0769,0.0379,0.9443,0.0705,0.4367],[0.5174,0.0018,0.0048,0.2058,0.0964,0.4359,0.0984,0.4296],[0.7111,0.0017,0.0031,0.1957,0.0924,0.3843,0.1129,0.4294]];
60
-
61
- const norm = [[],[],[]];
62
- for(let f=0;f<8;f++){
63
  const v = [raw[0][f], raw[1][f], raw[2][f]];
64
  const minVal = Math.min(...v);
65
  const range = Math.max(...v) - minVal || 1;
@@ -67,113 +67,195 @@ function createHeatmap(){
67
  norm[1].push((raw[1][f] - minVal) / range);
68
  norm[2].push((raw[2][f] - minVal) / range);
69
  }
70
-
71
- const ctx=document.getElementById('chart-heatmap');if(!ctx)return;
72
- const datasets=SEGS.map((s,si)=>({label:s,data:norm[si],raw_data:raw[si],backgroundColor:SEG_COLORS[si],borderRadius:4,borderSkipped:false}));
73
- new Chart(ctx,{type:'bar',data:{labels:feats,datasets},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{position:'bottom'},tooltip:{callbacks:{label:c=>c.dataset.label+': '+c.dataset.raw_data[c.dataIndex].toFixed(4)}}},scales:{y:{display:false,beginAtZero:true,max:1.1},x:{grid:{display:false},ticks:{font:{size:11},maxRotation:45}}}}});
74
  }
75
 
76
  /* ==================== TAB 2: SEGMENTS ==================== */
77
- function buildSegmentBars(){mkBar('chart-segment-bars',SEGS,[{label:'UC TRx/week',data:[0.1713,0.5174,0.7111],backgroundColor:SEG_COLORS,borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
78
- function buildMedMix(){mkBar('chart-med-mix',SEGS,[{label:'Total UC TRx',data:[0.1713,0.5174,0.7111],backgroundColor:'#6B7A96',borderRadius:4},{label:'IL-23 Biologic',data:[0.0127,0.0597,0.0941],backgroundColor:CC,borderRadius:4},{label:'Oral TRx',data:[0.0234,0.1257,0.1400],backgroundColor:CB,borderRadius:4}]);}
79
 
80
- function createPersonaFull(id,data,color){const ctx=document.getElementById(id);if(!ctx)return;new Chart(ctx,{type:'line',data:{labels:wk,datasets:[{label:'TRx Volume',data:data.trx,borderColor:color,backgroundColor:color+'10',fill:true,tension:0.4,borderWidth:3,pointRadius:0,pointHoverRadius:6,yAxisID:'y'},{label:'Engagement Score',data:data.eng,borderColor:AMBER,backgroundColor:'transparent',borderDash:[4,4],tension:0.4,borderWidth:2,pointRadius:0,pointHoverRadius:6,yAxisID:'y1'},{label:'New Rx (NRx)',data:data.nrx,borderColor:GREEN,backgroundColor:'transparent',tension:0.4,borderWidth:2,pointRadius:0,pointHoverRadius:6,yAxisID:'y1'}]},options:{responsive:true,maintainAspectRatio:false,interaction:{mode:'index',intersect:false},plugins:{legend:{position:'top'},tooltip:{mode:'index'}},scales:{y:{type:'linear',display:true,position:'left',beginAtZero:true,grid:{color:'#f1f5f9'},title:{display:true,text:'TRx / NRx Volume'}},y1:{type:'linear',display:true,position:'right',beginAtZero:true,grid:{drawOnChartArea:false},title:{display:true,text:'Marketing Interactions'}},x:{grid:{display:false},ticks:{maxTicksLimit:8}}}}});}
81
 
82
  /* ==================== TAB 3: ADOPTION ==================== */
83
- function buildAdoptionPct(){mkBar('chart-adoption-pct',SEGS,[{label:'Never Tried',data:[95.6,88.6,88.8],backgroundColor:RED,borderRadius:4},{label:'Active',data:[2.8,7.7,7.4],backgroundColor:GREEN,borderRadius:4},{label:'Lapsed',data:[1.6,3.7,3.8],backgroundColor:CC,borderRadius:4}],{extra:{plugins:{legend:{display:true,position:'bottom'}}},y:{stacked:true,max:105},x:{stacked:true}});}
84
- function buildAdoptionAbs(){mkBar('chart-adoption-abs',SEGS,[{label:'Never Tried',data:[6124,2967,1903],backgroundColor:RED,borderRadius:4},{label:'Active',data:[181,257,159],backgroundColor:GREEN,borderRadius:4},{label:'Lapsed',data:[101,125,82],backgroundColor:CC,borderRadius:4}]);}
85
- function buildGrowthSignals(){mkBar('chart-growth-signals',['B1 Growing (%)','New Adopter (%)','Active Last 8 Wks (%)'],[{label:'SEG_A',data:[3.79,3.72,2.83],backgroundColor:CA,borderRadius:4},{label:'SEG_B',data:[9.64,8.81,7.67],backgroundColor:CB,borderRadius:4},{label:'SEG_C',data:[9.24,8.44,7.42],backgroundColor:CC,borderRadius:4}]);}
86
- function buildTrendBars(){mkBar('chart-trend-bars',['SEG_A (Avg)','SEG_A (Recent)','SEG_B (Avg)','SEG_B (Recent)','SEG_C (Avg)','SEG_C (Recent)'],[{data:[0.000504,0.001325,0.001835,0.004195,0.001720,0.004224],backgroundColor:[CA,CA,CB,CB,CC,CC].map((c,i)=>i%2===0?c+'80':c),borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
87
 
88
  /* ==================== TAB 4: COMPETITIVE ==================== */
89
- function buildCompShare(){mkBar('chart-comp-share',SEGS,[{label:'Pfizer Share (%)',data:[0.363,0.480,0.311],backgroundColor:CB,borderRadius:4},{label:'Brand2 Share (%)',data:[1.429,2.153,1.250],backgroundColor:CC,borderRadius:4}]);}
90
- function buildCompRatio(){mkBar('chart-comp-ratio',SEGS,[{data:[3.90,4.43,4.29],backgroundColor:SEG_COLORS,borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
91
- function buildScatterUC(){const ctx=document.getElementById('chart-scatter-uc');if(!ctx)return;
92
- const mk=(n,ub,sb)=>{const d=[];for(let i=0;i<n;i++)d.push({x:Math.max(0,ub+Math.random()*ub*3),y:Math.max(0,Math.min(0.15,sb+Math.random()*sb*4-sb*1.5))});return d;};
93
- new Chart(ctx,{type:'scatter',data:{datasets:[{label:'SEG_A',data:mk(400,0.17,0.004),backgroundColor:CA+'66',pointRadius:3},{label:'SEG_B',data:mk(300,0.52,0.005),backgroundColor:CB+'66',pointRadius:3},{label:'SEG_C',data:mk(200,0.71,0.003),backgroundColor:CC+'66',pointRadius:3}]},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{position:'bottom'}},scales:{x:{title:{display:true,text:'UC TRx Mean (weekly)'},grid:{color:'#f1f5f9'}},y:{title:{display:true,text:'Pfizer Share of UC'},grid:{color:'#f1f5f9'}}}}});}
 
 
94
 
95
  /* ==================== TAB 5: ENGAGEMENT ==================== */
96
- function buildEngagement(){mkBar('chart-engagement',SEGS,[{label:'Details per Rx',data:[0.944,0.436,0.384],backgroundColor:SEG_COLORS,borderRadius:6,borderSkipped:false}],{plugins:{legend:{display:false}}});}
97
- function buildScatterEng(){const ctx=document.getElementById('chart-scatter-eng');if(!ctx)return;
98
- const mk=(n,db,bb)=>{const d=[];for(let i=0;i<n;i++)d.push({x:Math.max(0,db+Math.random()*db*3),y:Math.max(0,bb+Math.random()*bb*4-bb)});return d;};
99
- new Chart(ctx,{type:'scatter',data:{datasets:[{label:'SEG_A',data:mk(400,5.28,0.0005),backgroundColor:CA+'66',pointRadius:3},{label:'SEG_B',data:mk(300,8.94,0.0018),backgroundColor:CB+'66',pointRadius:3},{label:'SEG_C',data:mk(200,8.71,0.0017),backgroundColor:CC+'66',pointRadius:3}]},options:{maintainAspectRatio:false,responsive:true,plugins:{legend:{position:'bottom'}},scales:{x:{title:{display:true,text:'Total Rep Visits (86 wks)'},grid:{color:'#f1f5f9'}},y:{title:{display:true,text:'Pfizer TRx / week'},grid:{color:'#f1f5f9'}}}}});}
 
 
100
 
101
  /* ==================== TAB 6: OPPORTUNITY ==================== */
102
- function buildOpportunityCharts(){
103
- fetch('opportunity_data.json').then(r=>r.json()).then(data=>{
104
  // Add a tiny random jitter to the y-axis (Score) so overlapping points are visible
105
  // We keep the original 'uc' and 'sc' to show in tooltips
106
  const jitter = () => (Math.random() - 0.5) * 0.04;
107
- const nv=data.noVisits.map(h=>({x:h.uc, y:Math.max(0, h.sc + jitter()), ...h}));
108
- const cv=data.covered.map(h=>({x:h.uc, y:Math.max(0, h.sc + jitter()), ...h}));
109
-
110
  // Histogram
111
  const all = [...data.noVisits, ...data.covered];
112
- const scores = all.map(h=>h.sc);
113
  const minSc = Math.min(...scores);
114
  const maxSc = Math.max(...scores);
115
-
116
  const numBins = 20;
117
  const binWidth = (maxSc > minSc) ? (maxSc - minSc) / numBins : 1;
118
  let edges = [];
119
- for(let i=0; i<=numBins; i++) edges.push(minSc + i * binWidth);
120
-
121
  let bins = Array(numBins).fill(0);
122
  scores.forEach(s => {
123
  let b = Math.floor((s - minSc) / binWidth);
124
  if (b >= numBins) b = numBins - 1;
125
  bins[b]++;
126
  });
127
-
128
- const histLabels = edges.slice(0, -1).map((e, i) => ((e + edges[i+1])/2).toFixed(2));
129
- mkBar('chart-opp-hist', histLabels, [{data:bins, backgroundColor:CU+'cc', borderRadius:2, borderSkipped:false}], {plugins:{legend:{display:false}},x:{ticks:{maxTicksLimit:10,font:{size:10}}}});
130
 
131
  // Scatter Plot
132
- const ctx=document.getElementById('chart-opp-scatter');if(!ctx)return;
133
- const chart=new Chart(ctx,{type:'scatter',data:{datasets:[
134
- {label:'No Rep Visits',data:nv,backgroundColor:RED+'aa',pointRadius:4,pointStyle:'circle'},
135
- {label:'Covered',data:cv,backgroundColor:CB+'88',pointRadius:4,pointStyle:'rect'}
136
- ]},options:{maintainAspectRatio:false,responsive:true,
137
- plugins:{legend:{position:'bottom'},tooltip:{callbacks:{
138
- title:pts=>{const p=pts[0];return p.datasetIndex===0?'ID: '+p.raw.id:'Covered HCP';},
139
- label:p=>[`UC TRx: ${p.raw.uc.toFixed(4)}/wk`,`Score: ${p.raw.sc.toFixed(4)}`,p.raw.sp?`Specialty: ${p.raw.sp}`:'']
140
- }}},
141
- scales:{x:{title:{display:true,text:'UC TRx Mean (weekly)'},grid:{color:'#f1f5f9'}},y:{title:{display:true,text:'Opportunity Score'},grid:{color:'#f1f5f9'}}},
142
- onClick:(evt,els)=>{
143
- if(!els.length)return;
144
- const el=els[0],di=el.datasetIndex,idx=el.index;
145
- if(di!==0)return;
146
- const hcp=chart.data.datasets[0].data[idx];
147
- const panel=document.getElementById('hcp-detail-panel');
148
- document.getElementById('hcp-detail-title').textContent='NUEVO_ID: '+hcp.id;
149
- document.getElementById('hcp-detail-grid').innerHTML=
150
- `<div class="card kpi-card"><div class="kpi-label">HCP ID</div><div class="kpi-value" style="font-size:22px;color:${RED}">${hcp.id}</div></div>`+
151
- `<div class="card kpi-card"><div class="kpi-label">Specialty</div><div class="kpi-value" style="font-size:16px">${hcp.sp}</div></div>`+
152
- `<div class="card kpi-card"><div class="kpi-label">UC TRx / Week</div><div class="kpi-value" style="font-size:22px">${hcp.uc.toFixed(4)}</div></div>`+
153
- `<div class="card kpi-card"><div class="kpi-label">Opportunity Score</div><div class="kpi-value" style="font-size:22px;color:${CU}">${hcp.sc.toFixed(4)}</div></div>`+
154
- `<div class="card kpi-card"><div class="kpi-label">Active Weeks</div><div class="kpi-value" style="font-size:22px">${hcp.ap}%</div></div>`;
155
- panel.style.display='block';
156
- panel.scrollIntoView({behavior:'smooth',block:'nearest'});
 
 
 
 
 
 
 
 
 
157
  }
158
- }});
159
  });
160
  }
161
 
162
  /* ==================== TAB 7: SPECIALTY ==================== */
163
- function buildSpecialtyStack(){
164
- const sp=['GP/Family Med','Gastroenterology','Internal Med','Neuro/Rheum','Other Spec','Pharmacy'];
165
- mkHBar('chart-spec-stack',sp,[{label:'SEG_A',data:[25,6256,74,13,29,9],backgroundColor:CA},{label:'SEG_B',data:[8,3297,13,5,23,3],backgroundColor:CB},{label:'SEG_C',data:[2,2127,3,3,8,1],backgroundColor:CC}],{x:{stacked:true}});
166
  }
167
- function buildSpecialtyPct(){
168
- const sp=['GP/Family Med','Gastroenterology','Internal Med','Neuro/Rheum','Other Spec','Pharmacy'];
169
- const sa=[25,6256,74,13,29,9],sb=[8,3297,13,5,23,3],sc=[2,2127,3,3,8,1];
170
- const pctA=sa.map((_,i)=>{const t=sa[i]+sb[i]+sc[i];return t?+(sa[i]/t*100).toFixed(1):0;});
171
- const pctB=sb.map((_,i)=>{const t=sa[i]+sb[i]+sc[i];return t?+(sb[i]/t*100).toFixed(1):0;});
172
- const pctC=sc.map((_,i)=>{const t=sa[i]+sb[i]+sc[i];return t?+(sc[i]/t*100).toFixed(1):0;});
173
- mkHBar('chart-spec-pct',sp,[{label:'SEG_A %',data:pctA,backgroundColor:CA},{label:'SEG_B %',data:pctB,backgroundColor:CB},{label:'SEG_C %',data:pctC,backgroundColor:CC}],{x:{stacked:true,max:100}});
174
  }
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
  /* Init */
179
- document.addEventListener('DOMContentLoaded',()=>{initTabs();loadTab('tab-overview');animateCounters();});
 
2
  HCP Segmentation Dashboard β€” Chart.js Unified Engine
3
  All data from hcp_analysis_clean.parquet (191 columns)
4
  ============================================================ */
5
+ Chart.defaults.color = '#64748b'; Chart.defaults.borderColor = '#e2e8f0'; Chart.defaults.font.family = "'Inter',sans-serif"; Chart.defaults.font.size = 13;
6
+ Chart.defaults.plugins.legend.labels.usePointStyle = true; Chart.defaults.plugins.legend.labels.pointStyle = 'circle'; Chart.defaults.plugins.legend.labels.padding = 20;
7
+ Chart.defaults.plugins.tooltip.backgroundColor = '#1e293b'; Chart.defaults.plugins.tooltip.padding = 14; Chart.defaults.plugins.tooltip.cornerRadius = 8;
8
 
9
+ const PB = '#0051a5', PL = '#00a3e0', PD = '#0d009d', PS = '#54c8e8';
10
+ const CA = '#6B7280', CB = '#1A6FD4', CC = '#D4720A', CU = '#7C3AED';
11
+ const GREEN = '#0D9E6E', RED = '#DC3545', AMBER = '#d97706';
12
+ const SEGS = ['SEG_A', 'SEG_B', 'SEG_C'];
13
+ const SEG_COLORS = [CA, CB, CC];
14
 
15
  /* Simulated weekly persona data (illustrative timeline shapes) */
16
+ function gen(base, trend, noise, n) { const d = []; for (let i = 0; i < n; i++)d.push(Math.max(0, Math.round((base + trend * i + (Math.random() - 0.5) * noise) * 10) / 10)); return d; }
17
+ const W = 20, wk = Array.from({ length: W }, (_, i) => `W${(i + 1) * 4}`);
18
+ const P = { a: { trx: gen(12, 0, 1.5, W), eng: gen(2, 0.02, 0.5, W), nrx: gen(1, 0, 0.5, W) }, b: { trx: gen(8, 0.4, 2, W), eng: gen(5, 0.3, 1, W), nrx: gen(3, 0.25, 0.8, W) }, c: { trx: gen(5, 0.15, 1.5, W), eng: gen(3, 0.1, 1.2, W), nrx: gen(2, 0.08, 0.6, W) } };
19
 
20
  /* Helper: create a bar chart */
21
+ function mkBar(id, labels, datasets, opts = {}) {
22
+ const ctx = document.getElementById(id); if (!ctx) return null;
23
+ return new Chart(ctx, { type: 'bar', data: { labels, datasets }, options: { maintainAspectRatio: false, responsive: true, plugins: { legend: { display: datasets.length > 1, position: 'bottom' }, ...(opts.plugins || {}) }, scales: { y: { beginAtZero: true, grid: { color: '#f1f5f9' }, ...(opts.y || {}) }, x: { grid: { display: false }, ...(opts.x || {}) } }, ...(opts.extra || {}) } });
24
  }
25
 
26
  /* Helper: horizontal bar */
27
+ function mkHBar(id, labels, datasets, opts = {}) {
28
+ const ctx = document.getElementById(id); if (!ctx) return null;
29
+ return new Chart(ctx, { type: 'bar', data: { labels, datasets }, options: { maintainAspectRatio: false, responsive: true, indexAxis: 'y', plugins: { legend: { display: datasets.length > 1, position: 'bottom' } }, scales: { x: { beginAtZero: true, grid: { color: '#f1f5f9' }, ...(opts.x || {}) }, y: { grid: { display: false } } } } });
30
  }
31
 
32
  /* Tab System */
33
+ function initTabs() {
34
+ document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); btn.classList.add('active'); const p = document.getElementById(btn.dataset.tab); if (p) { p.classList.add('active'); if (!p.dataset.loaded) { loadTab(btn.dataset.tab); p.dataset.loaded = '1'; } } }); });
35
+ document.querySelectorAll('.sub-tab').forEach(btn => { btn.addEventListener('click', () => { const g = btn.closest('.sub-tabs'), ct = btn.closest('.tab-content') || document; g.querySelectorAll('.sub-tab').forEach(b => b.classList.remove('active')); ct.querySelectorAll('.sub-panel').forEach(p => p.classList.remove('active')); btn.classList.add('active'); const p = ct.querySelector(`#${btn.dataset.subtab}`); if (p) p.classList.add('active'); }); });
36
  }
37
 
38
+ function loadTab(id) {
39
+ if (id === 'tab-overview') { createFunnel(); createDoughnut(); createHeatmap(); }
40
+ if (id === 'tab-segments') { buildSegmentBars(); buildMedMix(); createPersonaFull('chart-pb-main', P.b, PL); createPersonaFull('chart-pc-main', P.c, PD); createPersonaFull('chart-pa-main', P.a, PB); }
41
+ if (id === 'tab-adoption') { buildAdoptionPct(); buildAdoptionAbs(); buildGrowthSignals(); buildTrendBars(); }
42
+ if (id === 'tab-competitive') { buildCompShare(); buildCompRatio(); buildScatterUC(); }
43
+ if (id === 'tab-engagement') { buildEngagement(); buildScatterEng(); }
44
+ if (id === 'tab-opportunity') { buildOpportunityCharts(); }
45
+ if (id === 'tab-specialty') { buildSpecialtyStack(); buildSpecialtyPct(); }
46
 
47
  }
48
 
49
  /* Counters */
50
+ function animateCounters() { document.querySelectorAll('[data-count]').forEach(el => { const t = parseFloat(el.dataset.count), sf = el.dataset.suffix || '', dur = 1200, st = performance.now(); (function u(now) { const p = Math.min((now - st) / dur, 1), v = t * (1 - Math.pow(1 - p, 3)); el.textContent = (el.dataset.count.includes('.') ? v.toFixed(1) : Math.round(v).toLocaleString()) + sf; if (p < 1) requestAnimationFrame(u); })(st); }); }
51
 
52
  /* ==================== TAB 1: OVERVIEW ==================== */
53
+ function createFunnel() { mkBar('chart-funnel', ['Total Market', 'Labeled', 'Unlabeled', 'SEG_A', 'SEG_B', 'SEG_C'], [{ data: [20931, 11899, 9032, 6406, 3349, 2144], backgroundColor: ['#e2e8f0', '#cbd5e1', '#94a3b8', PB, PL, PD], borderRadius: 6, borderSkipped: false }], { plugins: { legend: { display: false } } }); }
54
 
55
+ function createDoughnut() { const ctx = document.getElementById('chart-doughnut'); if (!ctx) return; new Chart(ctx, { type: 'doughnut', data: { labels: ['SEG_A (Traditional)', 'SEG_B (Relationship)', 'SEG_C (Didactic)'], datasets: [{ data: [6406, 3349, 2144], backgroundColor: [PB, PL, PD], borderColor: '#fff', borderWidth: 4, hoverOffset: 8 }] }, options: { maintainAspectRatio: false, cutout: '70%', responsive: true, plugins: { legend: { position: 'bottom' }, tooltip: { callbacks: { label: c => `${c.label}: ${c.raw.toLocaleString()} HCPs (${(c.raw / 11899 * 100).toFixed(1)}%)` } } } } }); }
56
 
57
+ function createHeatmap() {
58
+ const feats = ['UC TRx/wk', 'Pfizer TRx/wk', 'Pfizer Share', 'Trend Ratio', '% Growing', 'Details/Rx', 'Biologic Loyalty', 'New Patient Orient.'];
59
+ const raw = [[0.1713, 0.0005, 0.0036, 0.0769, 0.0379, 0.9443, 0.0705, 0.4367], [0.5174, 0.0018, 0.0048, 0.2058, 0.0964, 0.4359, 0.0984, 0.4296], [0.7111, 0.0017, 0.0031, 0.1957, 0.0924, 0.3843, 0.1129, 0.4294]];
60
+
61
+ const norm = [[], [], []];
62
+ for (let f = 0; f < 8; f++) {
63
  const v = [raw[0][f], raw[1][f], raw[2][f]];
64
  const minVal = Math.min(...v);
65
  const range = Math.max(...v) - minVal || 1;
 
67
  norm[1].push((raw[1][f] - minVal) / range);
68
  norm[2].push((raw[2][f] - minVal) / range);
69
  }
70
+
71
+ const ctx = document.getElementById('chart-heatmap'); if (!ctx) return;
72
+ const datasets = SEGS.map((s, si) => ({ label: s, data: norm[si], raw_data: raw[si], backgroundColor: SEG_COLORS[si], borderRadius: 4, borderSkipped: false }));
73
+ new Chart(ctx, { type: 'bar', data: { labels: feats, datasets }, options: { maintainAspectRatio: false, responsive: true, plugins: { legend: { position: 'bottom' }, tooltip: { callbacks: { label: c => c.dataset.label + ': ' + c.dataset.raw_data[c.dataIndex].toFixed(4) } } }, scales: { y: { display: false, beginAtZero: true, max: 1.1 }, x: { grid: { display: false }, ticks: { font: { size: 11 }, maxRotation: 45 } } } } });
74
  }
75
 
76
  /* ==================== TAB 2: SEGMENTS ==================== */
77
+ function buildSegmentBars() { mkBar('chart-segment-bars', SEGS, [{ label: 'UC TRx/week', data: [0.1713, 0.5174, 0.7111], backgroundColor: SEG_COLORS, borderRadius: 6, borderSkipped: false }], { plugins: { legend: { display: false } } }); }
78
+ function buildMedMix() { mkBar('chart-med-mix', SEGS, [{ label: 'Total UC TRx', data: [0.1713, 0.5174, 0.7111], backgroundColor: '#6B7A96', borderRadius: 4 }, { label: 'IL-23 Biologic', data: [0.0127, 0.0597, 0.0941], backgroundColor: CC, borderRadius: 4 }, { label: 'Oral TRx', data: [0.0234, 0.1257, 0.1400], backgroundColor: CB, borderRadius: 4 }]); }
79
 
80
+ function createPersonaFull(id, data, color) { const ctx = document.getElementById(id); if (!ctx) return; new Chart(ctx, { type: 'line', data: { labels: wk, datasets: [{ label: 'TRx Volume', data: data.trx, borderColor: color, backgroundColor: color + '10', fill: true, tension: 0.4, borderWidth: 3, pointRadius: 0, pointHoverRadius: 6, yAxisID: 'y' }, { label: 'Engagement Score', data: data.eng, borderColor: AMBER, backgroundColor: 'transparent', borderDash: [4, 4], tension: 0.4, borderWidth: 2, pointRadius: 0, pointHoverRadius: 6, yAxisID: 'y1' }, { label: 'New Rx (NRx)', data: data.nrx, borderColor: GREEN, backgroundColor: 'transparent', tension: 0.4, borderWidth: 2, pointRadius: 0, pointHoverRadius: 6, yAxisID: 'y1' }] }, options: { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false }, plugins: { legend: { position: 'top' }, tooltip: { mode: 'index' } }, scales: { y: { type: 'linear', display: true, position: 'left', beginAtZero: true, grid: { color: '#f1f5f9' }, title: { display: true, text: 'TRx / NRx Volume' } }, y1: { type: 'linear', display: true, position: 'right', beginAtZero: true, grid: { drawOnChartArea: false }, title: { display: true, text: 'Marketing Interactions' } }, x: { grid: { display: false }, ticks: { maxTicksLimit: 8 } } } } }); }
81
 
82
  /* ==================== TAB 3: ADOPTION ==================== */
83
+ function buildAdoptionPct() { mkBar('chart-adoption-pct', SEGS, [{ label: 'Never Tried', data: [95.6, 88.6, 88.8], backgroundColor: RED, borderRadius: 4 }, { label: 'Active', data: [2.8, 7.7, 7.4], backgroundColor: GREEN, borderRadius: 4 }, { label: 'Lapsed', data: [1.6, 3.7, 3.8], backgroundColor: CC, borderRadius: 4 }], { extra: { plugins: { legend: { display: true, position: 'bottom' } } }, y: { stacked: true, max: 105 }, x: { stacked: true } }); }
84
+ function buildAdoptionAbs() { mkBar('chart-adoption-abs', SEGS, [{ label: 'Never Tried', data: [6124, 2967, 1903], backgroundColor: RED, borderRadius: 4 }, { label: 'Active', data: [181, 257, 159], backgroundColor: GREEN, borderRadius: 4 }, { label: 'Lapsed', data: [101, 125, 82], backgroundColor: CC, borderRadius: 4 }]); }
85
+ function buildGrowthSignals() { mkBar('chart-growth-signals', ['B1 Growing (%)', 'New Adopter (%)', 'Active Last 8 Wks (%)'], [{ label: 'SEG_A', data: [3.79, 3.72, 2.83], backgroundColor: CA, borderRadius: 4 }, { label: 'SEG_B', data: [9.64, 8.81, 7.67], backgroundColor: CB, borderRadius: 4 }, { label: 'SEG_C', data: [9.24, 8.44, 7.42], backgroundColor: CC, borderRadius: 4 }]); }
86
+ function buildTrendBars() { mkBar('chart-trend-bars', ['SEG_A (Avg)', 'SEG_A (Recent)', 'SEG_B (Avg)', 'SEG_B (Recent)', 'SEG_C (Avg)', 'SEG_C (Recent)'], [{ data: [0.000504, 0.001325, 0.001835, 0.004195, 0.001720, 0.004224], backgroundColor: [CA, CA, CB, CB, CC, CC].map((c, i) => i % 2 === 0 ? c + '80' : c), borderRadius: 6, borderSkipped: false }], { plugins: { legend: { display: false } } }); }
87
 
88
  /* ==================== TAB 4: COMPETITIVE ==================== */
89
+ function buildCompShare() { mkBar('chart-comp-share', SEGS, [{ label: 'Pfizer Share (%)', data: [0.363, 0.480, 0.311], backgroundColor: CB, borderRadius: 4 }, { label: 'Brand2 Share (%)', data: [1.429, 2.153, 1.250], backgroundColor: CC, borderRadius: 4 }]); }
90
+ function buildCompRatio() { mkBar('chart-comp-ratio', SEGS, [{ data: [3.90, 4.43, 4.29], backgroundColor: SEG_COLORS, borderRadius: 6, borderSkipped: false }], { plugins: { legend: { display: false } } }); }
91
+ function buildScatterUC() {
92
+ const ctx = document.getElementById('chart-scatter-uc'); if (!ctx) return;
93
+ const mk = (n, ub, sb) => { const d = []; for (let i = 0; i < n; i++)d.push({ x: Math.max(0, ub + Math.random() * ub * 3), y: Math.max(0, Math.min(0.15, sb + Math.random() * sb * 4 - sb * 1.5)) }); return d; };
94
+ new Chart(ctx, { type: 'scatter', data: { datasets: [{ label: 'SEG_A', data: mk(400, 0.17, 0.004), backgroundColor: CA + '66', pointRadius: 3 }, { label: 'SEG_B', data: mk(300, 0.52, 0.005), backgroundColor: CB + '66', pointRadius: 3 }, { label: 'SEG_C', data: mk(200, 0.71, 0.003), backgroundColor: CC + '66', pointRadius: 3 }] }, options: { maintainAspectRatio: false, responsive: true, plugins: { legend: { position: 'bottom' } }, scales: { x: { title: { display: true, text: 'UC TRx Mean (weekly)' }, grid: { color: '#f1f5f9' } }, y: { title: { display: true, text: 'Pfizer Share of UC' }, grid: { color: '#f1f5f9' } } } } });
95
+ }
96
 
97
  /* ==================== TAB 5: ENGAGEMENT ==================== */
98
+ function buildEngagement() { mkBar('chart-engagement', SEGS, [{ label: 'Details per Rx', data: [0.944, 0.436, 0.384], backgroundColor: SEG_COLORS, borderRadius: 6, borderSkipped: false }], { plugins: { legend: { display: false } } }); }
99
+ function buildScatterEng() {
100
+ const ctx = document.getElementById('chart-scatter-eng'); if (!ctx) return;
101
+ const mk = (n, db, bb) => { const d = []; for (let i = 0; i < n; i++)d.push({ x: Math.max(0, db + Math.random() * db * 3), y: Math.max(0, bb + Math.random() * bb * 4 - bb) }); return d; };
102
+ new Chart(ctx, { type: 'scatter', data: { datasets: [{ label: 'SEG_A', data: mk(400, 5.28, 0.0005), backgroundColor: CA + '66', pointRadius: 3 }, { label: 'SEG_B', data: mk(300, 8.94, 0.0018), backgroundColor: CB + '66', pointRadius: 3 }, { label: 'SEG_C', data: mk(200, 8.71, 0.0017), backgroundColor: CC + '66', pointRadius: 3 }] }, options: { maintainAspectRatio: false, responsive: true, plugins: { legend: { position: 'bottom' } }, scales: { x: { title: { display: true, text: 'Total Rep Visits (86 wks)' }, grid: { color: '#f1f5f9' } }, y: { title: { display: true, text: 'Pfizer TRx / week' }, grid: { color: '#f1f5f9' } } } } });
103
+ }
104
 
105
  /* ==================== TAB 6: OPPORTUNITY ==================== */
106
+ function buildOpportunityCharts() {
107
+ fetch('opportunity_data.json').then(r => r.json()).then(data => {
108
  // Add a tiny random jitter to the y-axis (Score) so overlapping points are visible
109
  // We keep the original 'uc' and 'sc' to show in tooltips
110
  const jitter = () => (Math.random() - 0.5) * 0.04;
111
+ const nv = data.noVisits.map(h => ({ x: h.uc, y: Math.max(0, h.sc + jitter()), ...h }));
112
+ const cv = data.covered.map(h => ({ x: h.uc, y: Math.max(0, h.sc + jitter()), ...h }));
113
+
114
  // Histogram
115
  const all = [...data.noVisits, ...data.covered];
116
+ const scores = all.map(h => h.sc);
117
  const minSc = Math.min(...scores);
118
  const maxSc = Math.max(...scores);
119
+
120
  const numBins = 20;
121
  const binWidth = (maxSc > minSc) ? (maxSc - minSc) / numBins : 1;
122
  let edges = [];
123
+ for (let i = 0; i <= numBins; i++) edges.push(minSc + i * binWidth);
124
+
125
  let bins = Array(numBins).fill(0);
126
  scores.forEach(s => {
127
  let b = Math.floor((s - minSc) / binWidth);
128
  if (b >= numBins) b = numBins - 1;
129
  bins[b]++;
130
  });
131
+
132
+ const histLabels = edges.slice(0, -1).map((e, i) => ((e + edges[i + 1]) / 2).toFixed(2));
133
+ mkBar('chart-opp-hist', histLabels, [{ data: bins, backgroundColor: CU + 'cc', borderRadius: 2, borderSkipped: false }], { plugins: { legend: { display: false } }, x: { ticks: { maxTicksLimit: 10, font: { size: 10 } } } });
134
 
135
  // Scatter Plot
136
+ const ctx = document.getElementById('chart-opp-scatter'); if (!ctx) return;
137
+ const chart = new Chart(ctx, {
138
+ type: 'scatter', data: {
139
+ datasets: [
140
+ { label: 'No Rep Visits', data: nv, backgroundColor: RED + 'aa', pointRadius: 4, pointStyle: 'circle' },
141
+ { label: 'Covered', data: cv, backgroundColor: CB + '88', pointRadius: 4, pointStyle: 'rect' }
142
+ ]
143
+ }, options: {
144
+ maintainAspectRatio: false, responsive: true,
145
+ plugins: {
146
+ legend: { position: 'bottom' }, tooltip: {
147
+ callbacks: {
148
+ title: pts => { const p = pts[0]; return p.datasetIndex === 0 ? 'ID: ' + p.raw.id : 'Covered HCP'; },
149
+ label: p => [`UC TRx: ${p.raw.uc.toFixed(4)}/wk`, `Score: ${p.raw.sc.toFixed(4)}`, p.raw.sp ? `Specialty: ${p.raw.sp}` : '']
150
+ }
151
+ }
152
+ },
153
+ scales: { x: { title: { display: true, text: 'UC TRx Mean (weekly)' }, grid: { color: '#f1f5f9' } }, y: { title: { display: true, text: 'Opportunity Score' }, grid: { color: '#f1f5f9' } } },
154
+ onClick: (evt, els) => {
155
+ if (!els.length) return;
156
+ const el = els[0], di = el.datasetIndex, idx = el.index;
157
+ if (di !== 0) return;
158
+ const hcp = chart.data.datasets[0].data[idx];
159
+ const panel = document.getElementById('hcp-detail-panel');
160
+ document.getElementById('hcp-detail-title').textContent = 'NUEVO_ID: ' + hcp.id;
161
+ document.getElementById('hcp-detail-grid').innerHTML =
162
+ `<div class="card kpi-card"><div class="kpi-label">HCP ID</div><div class="kpi-value" style="font-size:22px;color:${RED}">${hcp.id}</div></div>` +
163
+ `<div class="card kpi-card"><div class="kpi-label">Specialty</div><div class="kpi-value" style="font-size:16px">${hcp.sp}</div></div>` +
164
+ `<div class="card kpi-card"><div class="kpi-label">UC TRx / Week</div><div class="kpi-value" style="font-size:22px">${hcp.uc.toFixed(4)}</div></div>` +
165
+ `<div class="card kpi-card"><div class="kpi-label">Opportunity Score</div><div class="kpi-value" style="font-size:22px;color:${CU}">${hcp.sc.toFixed(4)}</div></div>` +
166
+ `<div class="card kpi-card"><div class="kpi-label">Active Weeks</div><div class="kpi-value" style="font-size:22px">${hcp.ap}%</div></div>`;
167
+ panel.style.display = 'block';
168
+ panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
169
+ }
170
  }
171
+ });
172
  });
173
  }
174
 
175
  /* ==================== TAB 7: SPECIALTY ==================== */
176
+ function buildSpecialtyStack() {
177
+ const sp = ['GP/Family Med', 'Gastroenterology', 'Internal Med', 'Neuro/Rheum', 'Other Spec', 'Pharmacy'];
178
+ mkHBar('chart-spec-stack', sp, [{ label: 'SEG_A', data: [25, 6256, 74, 13, 29, 9], backgroundColor: CA }, { label: 'SEG_B', data: [8, 3297, 13, 5, 23, 3], backgroundColor: CB }, { label: 'SEG_C', data: [2, 2127, 3, 3, 8, 1], backgroundColor: CC }], { x: { stacked: true } });
179
  }
180
+ function buildSpecialtyPct() {
181
+ const sp = ['GP/Family Med', 'Gastroenterology', 'Internal Med', 'Neuro/Rheum', 'Other Spec', 'Pharmacy'];
182
+ const sa = [25, 6256, 74, 13, 29, 9], sb = [8, 3297, 13, 5, 23, 3], sc = [2, 2127, 3, 3, 8, 1];
183
+ const pctA = sa.map((_, i) => { const t = sa[i] + sb[i] + sc[i]; return t ? +(sa[i] / t * 100).toFixed(1) : 0; });
184
+ const pctB = sb.map((_, i) => { const t = sa[i] + sb[i] + sc[i]; return t ? +(sb[i] / t * 100).toFixed(1) : 0; });
185
+ const pctC = sc.map((_, i) => { const t = sa[i] + sb[i] + sc[i]; return t ? +(sc[i] / t * 100).toFixed(1) : 0; });
186
+ mkHBar('chart-spec-pct', sp, [{ label: 'SEG_A %', data: pctA, backgroundColor: CA }, { label: 'SEG_B %', data: pctB, backgroundColor: CB }, { label: 'SEG_C %', data: pctC, backgroundColor: CC }], { x: { stacked: true, max: 100 } });
187
  }
188
 
189
+ /* ============================================================
190
+ HUGGING FACE INFERENCE API INTEGRATION
191
+ Model: pfizer-project-team/binary-segA-vs-segBC
192
+ ============================================================ */
193
+
194
+ const HF_API_URL = "https://api-inference.huggingface.co/models/pfizer-project-team/binary-segA-vs-segBC";
195
+ // Note: If your model is private, you need a token. If it's public, you might not need it,
196
+ // but it is highly recommended to avoid rate limits.
197
+ const HF_TOKEN = "YOUR_HF_ACCESS_TOKEN";
198
+
199
+ async function runModelPrediction() {
200
+ const resultDiv = document.getElementById('prediction-result');
201
+ const predictBtn = document.getElementById('btn-predict');
202
 
203
+ // UI Loading state
204
+ resultDiv.style.display = 'block';
205
+ resultDiv.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Running inference on Hugging Face...';
206
+ predictBtn.disabled = true;
207
+ predictBtn.style.opacity = '0.5';
208
+
209
+ // Construct the payload.
210
+ // IMPORTANT: Modify the keys and array lengths to match the exact input features your model expects.
211
+ const payload = {
212
+ "inputs": {
213
+ "DETAILS__std": [2.5],
214
+ "COPAY__mean": [15.0],
215
+ "ORAL_NRX__slope": [0.001],
216
+ "UC_TRX__max": [12.0]
217
+ }
218
+ };
219
+
220
+ try {
221
+ const response = await fetch(HF_API_URL, {
222
+ method: "POST",
223
+ headers: {
224
+ "Authorization": `Bearer ${HF_TOKEN}`,
225
+ "Content-Type": "application/json"
226
+ },
227
+ body: JSON.stringify(payload)
228
+ });
229
+
230
+ if (!response.ok) {
231
+ throw new Error(`HTTP Status: ${response.status}`);
232
+ }
233
+
234
+ const data = await response.json();
235
+
236
+ // Format the output dynamically
237
+ // Scikit-learn / XGBoost models typically return an array of predictions
238
+ const predictionValue = Array.isArray(data) ? data[0] : JSON.stringify(data);
239
+
240
+ resultDiv.innerHTML = `<i class="fas fa-check-circle" style="color: var(--accent-green);"></i> Model Output: <b>${predictionValue}</b>`;
241
+
242
+ } catch (error) {
243
+ console.error("HF Inference API Error:", error);
244
+ resultDiv.innerHTML = `<i class="fas fa-exclamation-triangle" style="color: var(--accent-coral);"></i> Error running model. Please check the console.`;
245
+ } finally {
246
+ // Reset button state
247
+ predictBtn.disabled = false;
248
+ predictBtn.style.opacity = '1';
249
+ }
250
+ }
251
+
252
+ // Attach the event listener once the DOM is fully loaded
253
+ document.addEventListener('DOMContentLoaded', () => {
254
+ const predictBtn = document.getElementById('btn-predict');
255
+ if (predictBtn) {
256
+ predictBtn.addEventListener('click', runModelPrediction);
257
+ }
258
+ });
259
 
260
  /* Init */
261
+ document.addEventListener('DOMContentLoaded', () => { initTabs(); loadTab('tab-overview'); animateCounters(); });
index.html CHANGED
@@ -1,244 +1,531 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
 
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
6
- <title>HCP Segmentation Dashboard β€” Pfizer UC</title>
7
- <meta name="description" content="Longitudinal behavioral analysis for Ulcerative Colitis HCP segmentation β€” powered by 191-column deep analytics">
8
- <link rel="stylesheet" href="styles.css">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
10
-
11
- <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
 
12
  </head>
 
13
  <body>
14
 
15
- <!-- Top Header -->
16
- <header class="top-header">
17
- <div class="top-header-left">
18
- <img src="Pfizer_Logo_Color_RGB.png" alt="Pfizer">
19
- <h1>HCP Segmentation Insights</h1>
20
- <span>Ulcerative Colitis β€” 191-Feature Deep Analytics</span>
21
- </div>
22
- <div><span class="header-badge">Pipeline Stable</span></div>
23
- </header>
24
-
25
- <!-- Tab Navigation -->
26
- <nav class="tab-nav">
27
- <button class="tab-btn active" data-tab="tab-overview"><i class="fas fa-chart-pie"></i> Executive Summary</button>
28
- <button class="tab-btn" data-tab="tab-segments"><i class="fas fa-layer-group"></i> Segment Deep-Dive</button>
29
- <button class="tab-btn" data-tab="tab-adoption"><i class="fas fa-rocket"></i> Brand Adoption</button>
30
- <button class="tab-btn" data-tab="tab-competitive"><i class="fas fa-chess"></i> Competitive Intel</button>
31
- <button class="tab-btn" data-tab="tab-engagement"><i class="fas fa-handshake"></i> Rep Engagement</button>
32
- <button class="tab-btn" data-tab="tab-opportunity"><i class="fas fa-crosshairs"></i> Unlabeled Opportunity</button>
33
- <button class="tab-btn" data-tab="tab-specialty"><i class="fas fa-stethoscope"></i> Specialty Mix</button>
34
-
35
- </nav>
36
-
37
- <!-- ==================== TAB 1: EXECUTIVE SUMMARY ==================== -->
38
- <div id="tab-overview" class="tab-content active">
39
- <div class="section-header"><div class="section-icon"><i class="fas fa-chart-pie"></i></div><div><div class="section-title">Executive Summary</div><div class="section-subtitle">Real KPIs from 20,931 HCPs across 86-week longitudinal panel</div></div></div>
40
-
41
- <div class="grid-5">
42
- <div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Total HCPs</span><div class="kpi-icon" style="background:#f1f5f9;color:#64748b"><i class="fas fa-users"></i></div></div><div class="kpi-value" data-count="20931">0</div><div class="kpi-sub">86-week longitudinal panel</div></div>
43
- <div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Labeled Cohort</span><div class="kpi-icon" style="background:#eef6fc;color:var(--pfizer-blue)"><i class="fas fa-tag"></i></div></div><div class="kpi-value" data-count="11899">0</div><div class="kpi-sub">56.9% of total market</div></div>
44
- <div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Unlabeled Pool</span><div class="kpi-icon" style="background:#f5f3ff;color:var(--seg-unlabeled)"><i class="fas fa-search"></i></div></div><div class="kpi-value" data-count="633">0</div><div class="kpi-sub">Pending classification</div></div>
45
- <div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Feature Columns</span><div class="kpi-icon" style="background:#ecfaff;color:var(--pfizer-sky)"><i class="fas fa-database"></i></div></div><div class="kpi-value" data-count="191">0</div><div class="kpi-sub">7 feature blocks engineered</div></div>
46
- <div class="card kpi-card"><div class="kpi-top"><span class="kpi-label">Deep Learning Recall</span><div class="kpi-icon" style="background:#ecfdf5;color:var(--accent-green)"><i class="fas fa-brain"></i></div></div><div class="kpi-value" data-count="75" data-suffix="%">0</div><div class="kpi-sub">On minority class (SEG_C)</div></div>
47
- </div>
48
-
49
- <div class="alert-box alert-info" style="margin-top:20px"><i class="fas fa-info-circle"></i><span><strong>Data Source:</strong> All metrics are computed from <code>hcp_analysis_clean.parquet</code> (20,931 HCPs Γ— 191 columns). KPIs reflect real aggregated prescribing, engagement, and market share data across the 86-week observation window.</span></div>
50
-
51
- <div class="grid-2" style="margin-top:24px">
52
- <div class="card"><div class="chart-title">Population Distribution</div><div class="chart-container" style="height:300px"><canvas id="chart-funnel"></canvas></div></div>
53
- <div class="card"><div class="chart-title">Labeled Target Breakdown</div><div class="chart-container" style="height:300px"><canvas id="chart-doughnut"></canvas></div></div>
54
- </div>
55
- <div class="card" style="margin-top:24px"><div class="chart-title">Key Metrics by Segment (Labeled Cohort)</div><div class="chart-container" style="height:340px"><canvas id="chart-heatmap"></canvas></div></div>
56
- </div>
57
-
58
- <!-- ==================== TAB 2: SEGMENT DEEP-DIVE ==================== -->
59
- <div id="tab-segments" class="tab-content">
60
- <div class="section-header"><div class="section-icon"><i class="fas fa-layer-group"></i></div><div><div class="section-title">Segment Deep-Dive</div><div class="section-subtitle">Behavioral profiling from actual 191-column feature engineering</div></div></div>
61
-
62
- <div class="grid-3">
63
- <!-- Seg A -->
64
- <div class="card segment-card seg-a">
65
- <div class="segment-name" style="color:var(--seg-a)">Segment A β€” Traditional</div>
66
- <div class="segment-desc">Lowest prescribing volume (0.17 UC TRx/wk). Only 3.8% show Pfizer growth. Highest rep effort per Rx (0.94 details/TRx). Status-quo prescribers resistant to new therapies.</div>
67
- <div class="segment-stats">
68
- <div class="segment-stat"><span class="segment-stat-label">Population</span><span class="segment-stat-value">6,406 (53.8%)</span></div>
69
- <div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span class="segment-stat-value">0.171</span></div>
70
- <div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span class="segment-stat-value" style="color:var(--accent-coral)">0.36%</span></div>
71
- <div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span class="segment-stat-value">46.1%</span></div>
72
- <div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span class="segment-stat-value" style="color:var(--accent-coral)">0.94</span></div>
73
- <div style="margin-top:8px"><span class="badge badge-amber">Low Priority β€” Baseline</span></div>
74
- </div></div>
75
-
76
- <!-- Seg B -->
77
- <div class="card segment-card seg-b">
78
- <div class="segment-name" style="color:var(--seg-b)">Segment B β€” Relationship</div>
79
- <div class="segment-desc">Highest Pfizer growth signal (9.6% growing). Most efficient rep conversion (0.44 details/TRx). Broadest promo engagement (2.56 channels). The primary commercial target.</div>
80
- <div class="segment-stats">
81
- <div class="segment-stat"><span class="segment-stat-label">Population</span><span class="segment-stat-value">3,349 (28.2%)</span></div>
82
- <div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span class="segment-stat-value">0.517</span></div>
83
- <div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span class="segment-stat-value" style="color:var(--seg-b)">0.48%</span></div>
84
- <div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span class="segment-stat-value">73.3%</span></div>
85
- <div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span class="segment-stat-value" style="color:var(--accent-green)">0.44</span></div>
86
- <div style="margin-top:8px"><span class="badge badge-green">High Priority β€” Target</span></div>
87
- </div></div>
88
-
89
- <!-- Seg C -->
90
- <div class="card segment-card seg-c">
91
- <div class="segment-name" style="color:var(--seg-c)">Segment C β€” Didactic</div>
92
- <div class="segment-desc">Highest UC volume (0.71 TRx/wk) and strongest biologic loyalty (11.3% IL-23 share). Most efficient rep relationship (0.38 details/TRx). Protocol-driven, evidence-based HCPs.</div>
93
- <div class="segment-stats">
94
- <div class="segment-stat"><span class="segment-stat-label">Population</span><span class="segment-stat-value">2,144 (18.0%)</span></div>
95
- <div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span class="segment-stat-value">0.711</span></div>
96
- <div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span class="segment-stat-value" style="color:var(--seg-c)">0.31%</span></div>
97
- <div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span class="segment-stat-value">76.8%</span></div>
98
- <div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span class="segment-stat-value" style="color:var(--accent-green)">0.38</span></div>
99
- <div style="margin-top:8px"><span class="badge badge-sky">Upsell Target β€” Deep Learning Focus</span></div>
100
- </div></div>
101
- </div>
102
-
103
- <div class="grid-2" style="margin-top:24px">
104
- <div class="card"><div class="chart-title">UC TRx Volume by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-segment-bars"></canvas></div></div>
105
- <div class="card"><div class="chart-title">Medication Mix by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-med-mix"></canvas></div></div>
106
- </div>
107
-
108
- <!-- HCP 86-Week Timelines (restored from V1) -->
109
- <div class="section-header" style="margin-top:32px"><div class="section-icon"><i class="fas fa-chart-line"></i></div><div><div class="section-title">HCP Longitudinal Journeys</div><div class="section-subtitle">Visualizing the 86-week sequential data fed into the tensors</div></div></div>
110
- <div class="sub-tabs">
111
- <button class="sub-tab active" data-subtab="sub-pb">Dr. James Chen (SEG_B)</button>
112
- <button class="sub-tab" data-subtab="sub-pc">Dr. Sarah Williams (SEG_C)</button>
113
- <button class="sub-tab" data-subtab="sub-pa">Dr. Maria Lopez (SEG_A)</button>
114
- </div>
115
- <!-- Dr. Chen (SEG_B) -->
116
- <div id="sub-pb" class="sub-panel active">
117
- <div class="card persona-card">
118
- <div class="persona-header"><div class="persona-avatar" style="background:var(--pfizer-light)">JC</div><div><div class="persona-name">Dr. James Chen</div><div class="persona-role">San Francisco, CA β€” Relationship-Centric</div><div class="persona-seg" style="color:var(--pfizer-light)">Segment B</div></div></div>
119
- <div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
120
- <div class="persona-metric"><div class="persona-metric-label">Avg Weekly TRx Volume</div><div class="persona-metric-value">14.2</div></div>
121
- <div class="persona-metric"><div class="persona-metric-label">86-Week Interactions</div><div class="persona-metric-value">High</div></div>
122
- </div>
123
- <div class="chart-container" style="height:320px"><canvas id="chart-pb-main"></canvas></div>
124
- </div></div>
125
- <!-- Dr. Williams (SEG_C) -->
126
- <div id="sub-pc" class="sub-panel">
127
- <div class="card persona-card">
128
- <div class="persona-header"><div class="persona-avatar" style="background:var(--pfizer-deep)">SW</div><div><div class="persona-name">Dr. Sarah Williams</div><div class="persona-role">Chicago, IL β€” Didactic / Cautious</div><div class="persona-seg" style="color:var(--pfizer-deep)">Segment C</div></div></div>
129
- <div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
130
- <div class="persona-metric"><div class="persona-metric-label">Avg Weekly TRx Volume</div><div class="persona-metric-value">6.8</div></div>
131
- <div class="persona-metric"><div class="persona-metric-label">86-Week Interactions</div><div class="persona-metric-value">Moderate</div></div>
132
- </div>
133
- <div class="chart-container" style="height:320px"><canvas id="chart-pc-main"></canvas></div>
134
- </div></div>
135
- <!-- Dr. Lopez (SEG_A) -->
136
- <div id="sub-pa" class="sub-panel">
137
- <div class="card persona-card">
138
- <div class="persona-header"><div class="persona-avatar" style="background:var(--pfizer-blue)">ML</div><div><div class="persona-name">Dr. Maria Lopez</div><div class="persona-role">Houston, TX β€” Traditional Prescriber</div><div class="persona-seg" style="color:var(--pfizer-blue)">Segment A</div></div></div>
139
- <div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
140
- <div class="persona-metric"><div class="persona-metric-label">Avg Weekly TRx Volume</div><div class="persona-metric-value">12.0</div></div>
141
- <div class="persona-metric"><div class="persona-metric-label">86-Week Interactions</div><div class="persona-metric-value">Low</div></div>
142
- </div>
143
- <div class="chart-container" style="height:320px"><canvas id="chart-pa-main"></canvas></div>
144
- </div></div>
145
- </div>
146
-
147
- <!-- ==================== TAB 3: BRAND ADOPTION ==================== -->
148
- <div id="tab-adoption" class="tab-content">
149
- <div class="section-header"><div class="section-icon"><i class="fas fa-rocket"></i></div><div><div class="section-title">Brand1 Adoption & Trajectory</div><div class="section-subtitle">Adoption funnel, growth signals, and recency trends from real data</div></div></div>
150
-
151
- <div class="grid-3" style="margin-bottom:24px">
152
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-coral)">91.4%</div><div class="metric-highlight-label">Never Tried Brand1</div></div>
153
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-green)">5.0%</div><div class="metric-highlight-label">Currently Active</div></div>
154
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-amber)">2.6%</div><div class="metric-highlight-label">Trialed Then Lapsed</div></div>
155
- </div>
156
-
157
- <div class="grid-2">
158
- <div class="card"><div class="chart-title">Adoption Funnel by Segment (% of each segment)</div><div class="chart-container" style="height:300px"><canvas id="chart-adoption-pct"></canvas></div></div>
159
- <div class="card"><div class="chart-title">Adoption Funnel by Segment (Absolute Count)</div><div class="chart-container" style="height:300px"><canvas id="chart-adoption-abs"></canvas></div></div>
160
- </div>
161
-
162
- <div class="grid-2" style="margin-top:24px">
163
- <div class="card"><div class="chart-title">Growth Signals: Who Is Accelerating?</div><div class="chart-container" style="height:300px"><canvas id="chart-growth-signals"></canvas></div></div>
164
- <div class="card"><div class="chart-title">Pfizer TRx: 86-Week Average vs. Recent 8 Weeks</div><div class="chart-container" style="height:300px"><canvas id="chart-trend-bars"></canvas></div></div>
165
- </div>
166
- </div>
167
-
168
- <!-- ==================== TAB 4: COMPETITIVE INTELLIGENCE ==================== -->
169
- <div id="tab-competitive" class="tab-content">
170
- <div class="section-header"><div class="section-icon"><i class="fas fa-chess"></i></div><div><div class="section-title">Competitive Intelligence</div><div class="section-subtitle">Pfizer vs Brand2 market dynamics across segments</div></div></div>
171
-
172
- <div class="grid-3" style="margin-bottom:24px">
173
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-a)">3.90Γ—</div><div class="metric-highlight-label">Brand2/Pfizer β€” SEG_A</div></div>
174
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-b)">4.43Γ—</div><div class="metric-highlight-label">Brand2/Pfizer β€” SEG_B</div></div>
175
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-c)">4.29Γ—</div><div class="metric-highlight-label">Brand2/Pfizer β€” SEG_C</div></div>
176
- </div>
177
-
178
- <div class="alert-box alert-warning"><i class="fas fa-exclamation-triangle"></i><span><strong>Competitive Pressure:</strong> Brand2 outprescribes Pfizer by 3.9–4.4Γ— across all segments. The gap is widest in SEG_B (4.43Γ—), the very segment with the highest Pfizer growth trajectory β€” indicating an active battleground for share.</span></div>
179
-
180
- <div class="grid-2" style="margin-top:24px">
181
- <div class="card"><div class="chart-title">Pfizer vs Brand2: Market Share of UC (%) by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-comp-share"></canvas></div></div>
182
- <div class="card"><div class="chart-title">Brand2/Pfizer Prescribing Ratio by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-comp-ratio"></canvas></div></div>
183
- </div>
184
-
185
- <div class="card" style="margin-top:24px"><div class="chart-title">UC TRx Volume vs Pfizer Market Share (Labeled HCPs)</div><div class="chart-container" style="height:420px"><canvas id="chart-scatter-uc"></canvas></div></div>
186
- </div>
187
-
188
- <!-- ==================== TAB 5: REP ENGAGEMENT ==================== -->
189
- <div id="tab-engagement" class="tab-content">
190
- <div class="section-header"><div class="section-icon"><i class="fas fa-handshake"></i></div><div><div class="section-title">Rep Engagement ROI</div><div class="section-subtitle">Measuring commercial efficiency: visits, channels, and prescribing impact</div></div></div>
191
-
192
- <div class="grid-4" style="margin-bottom:24px">
193
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-a)">0.94</div><div class="metric-highlight-label">Details/Rx β€” SEG_A</div></div>
194
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-b)">0.44</div><div class="metric-highlight-label">Details/Rx β€” SEG_B</div></div>
195
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--seg-c)">0.38</div><div class="metric-highlight-label">Details/Rx β€” SEG_C</div></div>
196
- <div class="card metric-highlight"><div class="metric-highlight-value" style="color:var(--accent-green)">2.1Γ—</div><div class="metric-highlight-label">SEG_B is 2.1Γ— more efficient than SEG_A</div></div>
197
- </div>
198
-
199
- <div class="grid-2">
200
- <div class="card"><div class="chart-title">Engagement Metrics by Segment</div><div class="chart-container" style="height:300px"><canvas id="chart-engagement"></canvas></div></div>
201
- <div class="card"><div class="chart-title">Rep Visits vs Pfizer Prescribing (Scatter)</div><div class="chart-container" style="height:300px"><canvas id="chart-scatter-eng"></canvas></div></div>
202
- </div>
203
- </div>
204
-
205
- <!-- ==================== TAB 6: UNLABELED OPPORTUNITY ==================== -->
206
- <div id="tab-opportunity" class="tab-content">
207
- <div class="section-header"><div class="section-icon"><i class="fas fa-crosshairs"></i></div><div><div class="section-title">Unlabeled HCP Opportunity</div><div class="section-subtitle">Prioritizing 633 unclassified HCPs for commercial outreach</div></div></div>
208
-
209
- <div class="grid-3" style="margin-bottom:24px">
210
- <div class="card tier-card tier-1"><div class="tier-value" style="color:var(--accent-green)">43</div><div class="tier-label">Tier 1 β€” Immediate</div><div class="tier-desc">Score β‰₯ 0.60. Highest prescribing + growth signals.</div></div>
211
- <div class="card tier-card tier-2"><div class="tier-value" style="color:var(--accent-amber)">22</div><div class="tier-label">Tier 2 β€” Validate</div><div class="tier-desc">Score 0.35–0.60. Moderate opportunity, needs validation.</div></div>
212
- <div class="card tier-card tier-3"><div class="tier-value" style="color:var(--text-muted)">568</div><div class="tier-label">Tier 3 β€” Monitor</div><div class="tier-desc">Score < 0.35. Low activity, monitor for emergence.</div></div>
213
- </div>
214
-
215
- <div class="alert-box alert-warning"><i class="fas fa-exclamation-triangle"></i><span><strong>Coverage Gap:</strong> 347 of 633 unlabeled HCPs (54.8%) have zero rep visits. Among Tier 1 (high-opportunity) HCPs, many prescribe actively but have never been contacted by a sales representative.</span></div>
216
-
217
- <div class="grid-2" style="margin-top:24px">
218
- <div class="card"><div class="chart-title">Opportunity Score Distribution (633 Unlabeled HCPs)</div><div class="chart-container" style="height:300px"><canvas id="chart-opp-hist"></canvas></div></div>
219
- <div class="card"><div class="chart-title">Click a red point to identify the HCP below ↓</div><div class="chart-container" style="height:300px"><canvas id="chart-opp-scatter"></canvas></div></div>
220
- </div>
221
-
222
- <!-- HCP Detail Panel (populated on click) -->
223
- <div id="hcp-detail-panel" class="card" style="margin-top:24px;display:none;border-left:4px solid var(--accent-coral)">
224
- <div class="section-header" style="margin-bottom:16px"><div class="section-icon" style="background:#fef2f2;color:var(--accent-coral)"><i class="fas fa-user-md"></i></div><div><div class="section-title" id="hcp-detail-title">HCP Selected</div><div class="section-subtitle">Zero rep visits β€” high opportunity for outreach</div></div></div>
225
- <div class="grid-5" id="hcp-detail-grid"></div>
226
- <div class="alert-box alert-warning" style="margin-top:16px"><i class="fas fa-bullhorn"></i><span><strong>Action Required:</strong> This HCP has never been visited by a sales representative yet shows significant UC prescribing activity. Recommend scheduling an initial detail call.</span></div>
227
- </div>
228
- </div>
229
-
230
- <!-- ==================== TAB 7: SPECIALTY MIX ==================== -->
231
- <div id="tab-specialty" class="tab-content">
232
- <div class="section-header"><div class="section-icon"><i class="fas fa-stethoscope"></i></div><div><div class="section-title">Specialty & Demographics</div><div class="section-subtitle">HCP specialty distribution across segments</div></div></div>
233
-
234
- <div class="grid-2">
235
- <div class="card"><div class="chart-title">HCPs by Specialty and Segment (Stacked)</div><div class="chart-container" style="height:300px"><canvas id="chart-spec-stack"></canvas></div></div>
236
- <div class="card"><div class="chart-title">Specialty Composition (% within each specialty)</div><div class="chart-container" style="height:300px"><canvas id="chart-spec-pct"></canvas></div></div>
237
- </div>
238
- </div>
239
-
240
-
241
-
242
- <script src="app.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  </body>
244
- </html>
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
+
4
  <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+ <title>HCP Segmentation Dashboard β€” Pfizer UC</title>
8
+ <meta name="description"
9
+ content="Longitudinal behavioral analysis for Ulcerative Colitis HCP segmentation β€” powered by 191-column deep analytics">
10
+ <link rel="stylesheet" href="styles.css">
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
12
+
13
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
14
  </head>
15
+
16
  <body>
17
 
18
+ <!-- Top Header -->
19
+ <header class="top-header">
20
+ <div class="top-header-left">
21
+ <img src="Pfizer_Logo_Color_RGB.png" alt="Pfizer">
22
+ <h1>HCP Segmentation Insights</h1>
23
+ <span>Ulcerative Colitis β€” 191-Feature Deep Analytics</span>
24
+ </div>
25
+ <div><span class="header-badge">Pipeline Stable</span></div>
26
+ </header>
27
+
28
+ <!-- Tab Navigation -->
29
+ <nav class="tab-nav">
30
+ <button class="tab-btn active" data-tab="tab-overview"><i class="fas fa-chart-pie"></i> Executive
31
+ Summary</button>
32
+ <button class="tab-btn" data-tab="tab-segments"><i class="fas fa-layer-group"></i> Segment Deep-Dive</button>
33
+ <button class="tab-btn" data-tab="tab-adoption"><i class="fas fa-rocket"></i> Brand Adoption</button>
34
+ <button class="tab-btn" data-tab="tab-competitive"><i class="fas fa-chess"></i> Competitive Intel</button>
35
+ <button class="tab-btn" data-tab="tab-engagement"><i class="fas fa-handshake"></i> Rep Engagement</button>
36
+ <button class="tab-btn" data-tab="tab-opportunity"><i class="fas fa-crosshairs"></i> Unlabeled
37
+ Opportunity</button>
38
+ <button class="tab-btn" data-tab="tab-specialty"><i class="fas fa-stethoscope"></i> Specialty Mix</button>
39
+
40
+ </nav>
41
+
42
+ <!-- ==================== TAB 1: EXECUTIVE SUMMARY ==================== -->
43
+ <div id="tab-overview" class="tab-content active">
44
+ <div class="section-header">
45
+ <div class="section-icon"><i class="fas fa-chart-pie"></i></div>
46
+ <div>
47
+ <div class="section-title">Executive Summary</div>
48
+ <div class="section-subtitle">Real KPIs from 20,931 HCPs across 86-week longitudinal panel</div>
49
+ </div>
50
+ </div>
51
+
52
+ <div class="grid-5">
53
+ <div class="card kpi-card">
54
+ <div class="kpi-top"><span class="kpi-label">Total HCPs</span>
55
+ <div class="kpi-icon" style="background:#f1f5f9;color:#64748b"><i class="fas fa-users"></i></div>
56
+ </div>
57
+ <div class="kpi-value" data-count="20931">0</div>
58
+ <div class="kpi-sub">86-week longitudinal panel</div>
59
+ </div>
60
+ <div class="card kpi-card">
61
+ <div class="kpi-top"><span class="kpi-label">Labeled Cohort</span>
62
+ <div class="kpi-icon" style="background:#eef6fc;color:var(--pfizer-blue)"><i class="fas fa-tag"></i>
63
+ </div>
64
+ </div>
65
+ <div class="kpi-value" data-count="11899">0</div>
66
+ <div class="kpi-sub">56.9% of total market</div>
67
+ </div>
68
+ <div class="card kpi-card">
69
+ <div class="kpi-top"><span class="kpi-label">Unlabeled Pool</span>
70
+ <div class="kpi-icon" style="background:#f5f3ff;color:var(--seg-unlabeled)"><i
71
+ class="fas fa-search"></i></div>
72
+ </div>
73
+ <div class="kpi-value" data-count="633">0</div>
74
+ <div class="kpi-sub">Pending classification</div>
75
+ </div>
76
+ <div class="card kpi-card">
77
+ <div class="kpi-top"><span class="kpi-label">Feature Columns</span>
78
+ <div class="kpi-icon" style="background:#ecfaff;color:var(--pfizer-sky)"><i
79
+ class="fas fa-database"></i></div>
80
+ </div>
81
+ <div class="kpi-value" data-count="191">0</div>
82
+ <div class="kpi-sub">7 feature blocks engineered</div>
83
+ </div>
84
+ <div class="card kpi-card">
85
+ <div class="kpi-top"><span class="kpi-label">Deep Learning Recall</span>
86
+ <div class="kpi-icon" style="background:#ecfdf5;color:var(--accent-green)"><i
87
+ class="fas fa-brain"></i></div>
88
+ </div>
89
+ <div class="kpi-value" data-count="75" data-suffix="%">0</div>
90
+ <div class="kpi-sub">On minority class (SEG_C)</div>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="alert-box alert-info" style="margin-top:20px"><i class="fas fa-info-circle"></i><span><strong>Data
95
+ Source:</strong> All metrics are computed from <code>hcp_analysis_clean.parquet</code> (20,931 HCPs
96
+ Γ— 191 columns). KPIs reflect real aggregated prescribing, engagement, and market share data across the
97
+ 86-week observation window.</span></div>
98
+
99
+ <div class="grid-2" style="margin-top:24px">
100
+ <div class="card">
101
+ <div class="chart-title">Population Distribution</div>
102
+ <div class="chart-container" style="height:300px"><canvas id="chart-funnel"></canvas></div>
103
+ </div>
104
+ <div class="card">
105
+ <div class="chart-title">Labeled Target Breakdown</div>
106
+ <div class="chart-container" style="height:300px"><canvas id="chart-doughnut"></canvas></div>
107
+ </div>
108
+ </div>
109
+ <div class="card" style="margin-top:24px">
110
+ <div class="chart-title">Key Metrics by Segment (Labeled Cohort)</div>
111
+ <div class="chart-container" style="height:340px"><canvas id="chart-heatmap"></canvas></div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- ==================== TAB 2: SEGMENT DEEP-DIVE ==================== -->
116
+ <div id="tab-segments" class="tab-content">
117
+ <div class="section-header">
118
+ <div class="section-icon"><i class="fas fa-layer-group"></i></div>
119
+ <div>
120
+ <div class="section-title">Segment Deep-Dive</div>
121
+ <div class="section-subtitle">Behavioral profiling from actual 191-column feature engineering</div>
122
+ </div>
123
+ </div>
124
+
125
+ <div class="grid-3">
126
+ <!-- Seg A -->
127
+ <div class="card segment-card seg-a">
128
+ <div class="segment-name" style="color:var(--seg-a)">Segment A β€” Traditional</div>
129
+ <div class="segment-desc">Lowest prescribing volume (0.17 UC TRx/wk). Only 3.8% show Pfizer growth.
130
+ Highest rep effort per Rx (0.94 details/TRx). Status-quo prescribers resistant to new therapies.
131
+ </div>
132
+ <div class="segment-stats">
133
+ <div class="segment-stat"><span class="segment-stat-label">Population</span><span
134
+ class="segment-stat-value">6,406 (53.8%)</span></div>
135
+ <div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span
136
+ class="segment-stat-value">0.171</span></div>
137
+ <div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span
138
+ class="segment-stat-value" style="color:var(--accent-coral)">0.36%</span></div>
139
+ <div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span
140
+ class="segment-stat-value">46.1%</span></div>
141
+ <div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span
142
+ class="segment-stat-value" style="color:var(--accent-coral)">0.94</span></div>
143
+ <div style="margin-top:8px"><span class="badge badge-amber">Low Priority β€” Baseline</span></div>
144
+ </div>
145
+ </div>
146
+
147
+ <!-- Seg B -->
148
+ <div class="card segment-card seg-b">
149
+ <div class="segment-name" style="color:var(--seg-b)">Segment B β€” Relationship</div>
150
+ <div class="segment-desc">Highest Pfizer growth signal (9.6% growing). Most efficient rep conversion
151
+ (0.44 details/TRx). Broadest promo engagement (2.56 channels). The primary commercial target.</div>
152
+ <div class="segment-stats">
153
+ <div class="segment-stat"><span class="segment-stat-label">Population</span><span
154
+ class="segment-stat-value">3,349 (28.2%)</span></div>
155
+ <div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span
156
+ class="segment-stat-value">0.517</span></div>
157
+ <div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span
158
+ class="segment-stat-value" style="color:var(--seg-b)">0.48%</span></div>
159
+ <div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span
160
+ class="segment-stat-value">73.3%</span></div>
161
+ <div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span
162
+ class="segment-stat-value" style="color:var(--accent-green)">0.44</span></div>
163
+ <div style="margin-top:8px"><span class="badge badge-green">High Priority β€” Target</span></div>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- Seg C -->
168
+ <div class="card segment-card seg-c">
169
+ <div class="segment-name" style="color:var(--seg-c)">Segment C β€” Didactic</div>
170
+ <div class="segment-desc">Highest UC volume (0.71 TRx/wk) and strongest biologic loyalty (11.3% IL-23
171
+ share). Most efficient rep relationship (0.38 details/TRx). Protocol-driven, evidence-based HCPs.
172
+ </div>
173
+ <div class="segment-stats">
174
+ <div class="segment-stat"><span class="segment-stat-label">Population</span><span
175
+ class="segment-stat-value">2,144 (18.0%)</span></div>
176
+ <div class="segment-stat"><span class="segment-stat-label">UC TRx/week</span><span
177
+ class="segment-stat-value">0.711</span></div>
178
+ <div class="segment-stat"><span class="segment-stat-label">Pfizer Share of UC</span><span
179
+ class="segment-stat-value" style="color:var(--seg-c)">0.31%</span></div>
180
+ <div class="segment-stat"><span class="segment-stat-label">Active Weeks</span><span
181
+ class="segment-stat-value">76.8%</span></div>
182
+ <div class="segment-stat"><span class="segment-stat-label">Details per Rx</span><span
183
+ class="segment-stat-value" style="color:var(--accent-green)">0.38</span></div>
184
+ <div style="margin-top:8px"><span class="badge badge-sky">Upsell Target β€” Deep Learning Focus</span>
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </div>
189
+
190
+ <div class="grid-2" style="margin-top:24px">
191
+ <div class="card">
192
+ <div class="chart-title">UC TRx Volume by Segment</div>
193
+ <div class="chart-container" style="height:300px"><canvas id="chart-segment-bars"></canvas></div>
194
+ </div>
195
+ <div class="card">
196
+ <div class="chart-title">Medication Mix by Segment</div>
197
+ <div class="chart-container" style="height:300px"><canvas id="chart-med-mix"></canvas></div>
198
+ </div>
199
+ </div>
200
+
201
+ <!-- HCP 86-Week Timelines (restored from V1) -->
202
+ <div class="section-header" style="margin-top:32px">
203
+ <div class="section-icon"><i class="fas fa-chart-line"></i></div>
204
+ <div>
205
+ <div class="section-title">HCP Longitudinal Journeys</div>
206
+ <div class="section-subtitle">Visualizing the 86-week sequential data fed into the tensors</div>
207
+ </div>
208
+ </div>
209
+ <div class="sub-tabs">
210
+ <button class="sub-tab active" data-subtab="sub-pb">Dr. James Chen (SEG_B)</button>
211
+ <button class="sub-tab" data-subtab="sub-pc">Dr. Sarah Williams (SEG_C)</button>
212
+ <button class="sub-tab" data-subtab="sub-pa">Dr. Maria Lopez (SEG_A)</button>
213
+ </div>
214
+ <!-- Dr. Chen (SEG_B) -->
215
+ <div id="sub-pb" class="sub-panel active">
216
+ <div class="card persona-card">
217
+ <div class="persona-header">
218
+ <div class="persona-avatar" style="background:var(--pfizer-light)">JC</div>
219
+ <div>
220
+ <div class="persona-name">Dr. James Chen</div>
221
+ <div class="persona-role">San Francisco, CA β€” Relationship-Centric</div>
222
+ <div class="persona-seg" style="color:var(--pfizer-light)">Segment B</div>
223
+ </div>
224
+ </div>
225
+ <div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
226
+ <div class="persona-metric">
227
+ <div class="persona-metric-label">Avg Weekly TRx Volume</div>
228
+ <div class="persona-metric-value">14.2</div>
229
+ </div>
230
+ <div class="persona-metric">
231
+ <div class="persona-metric-label">86-Week Interactions</div>
232
+ <div class="persona-metric-value">High</div>
233
+ </div>
234
+ </div>
235
+ <div class="chart-container" style="height:320px"><canvas id="chart-pb-main"></canvas></div>
236
+ </div>
237
+ </div>
238
+ <!-- Dr. Williams (SEG_C) -->
239
+ <div id="sub-pc" class="sub-panel">
240
+ <div class="card persona-card">
241
+ <div class="persona-header">
242
+ <div class="persona-avatar" style="background:var(--pfizer-deep)">SW</div>
243
+ <div>
244
+ <div class="persona-name">Dr. Sarah Williams</div>
245
+ <div class="persona-role">Chicago, IL β€” Didactic / Cautious</div>
246
+ <div class="persona-seg" style="color:var(--pfizer-deep)">Segment C</div>
247
+ </div>
248
+ </div>
249
+ <div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
250
+ <div class="persona-metric">
251
+ <div class="persona-metric-label">Avg Weekly TRx Volume</div>
252
+ <div class="persona-metric-value">6.8</div>
253
+ </div>
254
+ <div class="persona-metric">
255
+ <div class="persona-metric-label">86-Week Interactions</div>
256
+ <div class="persona-metric-value">Moderate</div>
257
+ </div>
258
+ </div>
259
+ <div class="chart-container" style="height:320px"><canvas id="chart-pc-main"></canvas></div>
260
+ </div>
261
+ </div>
262
+ <!-- Dr. Lopez (SEG_A) -->
263
+ <div id="sub-pa" class="sub-panel">
264
+ <div class="card persona-card">
265
+ <div class="persona-header">
266
+ <div class="persona-avatar" style="background:var(--pfizer-blue)">ML</div>
267
+ <div>
268
+ <div class="persona-name">Dr. Maria Lopez</div>
269
+ <div class="persona-role">Houston, TX β€” Traditional Prescriber</div>
270
+ <div class="persona-seg" style="color:var(--pfizer-blue)">Segment A</div>
271
+ </div>
272
+ </div>
273
+ <div class="persona-detail-grid" style="margin-top:0;margin-bottom:24px">
274
+ <div class="persona-metric">
275
+ <div class="persona-metric-label">Avg Weekly TRx Volume</div>
276
+ <div class="persona-metric-value">12.0</div>
277
+ </div>
278
+ <div class="persona-metric">
279
+ <div class="persona-metric-label">86-Week Interactions</div>
280
+ <div class="persona-metric-value">Low</div>
281
+ </div>
282
+ </div>
283
+ <div class="chart-container" style="height:320px"><canvas id="chart-pa-main"></canvas></div>
284
+ </div>
285
+ </div>
286
+ </div>
287
+
288
+ <!-- ==================== TAB 3: BRAND ADOPTION ==================== -->
289
+ <div id="tab-adoption" class="tab-content">
290
+ <div class="section-header">
291
+ <div class="section-icon"><i class="fas fa-rocket"></i></div>
292
+ <div>
293
+ <div class="section-title">Brand1 Adoption & Trajectory</div>
294
+ <div class="section-subtitle">Adoption funnel, growth signals, and recency trends from real data</div>
295
+ </div>
296
+ </div>
297
+
298
+ <div class="grid-3" style="margin-bottom:24px">
299
+ <div class="card metric-highlight">
300
+ <div class="metric-highlight-value" style="color:var(--accent-coral)">91.4%</div>
301
+ <div class="metric-highlight-label">Never Tried Brand1</div>
302
+ </div>
303
+ <div class="card metric-highlight">
304
+ <div class="metric-highlight-value" style="color:var(--accent-green)">5.0%</div>
305
+ <div class="metric-highlight-label">Currently Active</div>
306
+ </div>
307
+ <div class="card metric-highlight">
308
+ <div class="metric-highlight-value" style="color:var(--accent-amber)">2.6%</div>
309
+ <div class="metric-highlight-label">Trialed Then Lapsed</div>
310
+ </div>
311
+ </div>
312
+
313
+ <div class="grid-2">
314
+ <div class="card">
315
+ <div class="chart-title">Adoption Funnel by Segment (% of each segment)</div>
316
+ <div class="chart-container" style="height:300px"><canvas id="chart-adoption-pct"></canvas></div>
317
+ </div>
318
+ <div class="card">
319
+ <div class="chart-title">Adoption Funnel by Segment (Absolute Count)</div>
320
+ <div class="chart-container" style="height:300px"><canvas id="chart-adoption-abs"></canvas></div>
321
+ </div>
322
+ </div>
323
+
324
+ <div class="grid-2" style="margin-top:24px">
325
+ <div class="card">
326
+ <div class="chart-title">Growth Signals: Who Is Accelerating?</div>
327
+ <div class="chart-container" style="height:300px"><canvas id="chart-growth-signals"></canvas></div>
328
+ </div>
329
+ <div class="card">
330
+ <div class="chart-title">Pfizer TRx: 86-Week Average vs. Recent 8 Weeks</div>
331
+ <div class="chart-container" style="height:300px"><canvas id="chart-trend-bars"></canvas></div>
332
+ </div>
333
+ </div>
334
+ </div>
335
+
336
+ <!-- ==================== TAB 4: COMPETITIVE INTELLIGENCE ==================== -->
337
+ <div id="tab-competitive" class="tab-content">
338
+ <div class="section-header">
339
+ <div class="section-icon"><i class="fas fa-chess"></i></div>
340
+ <div>
341
+ <div class="section-title">Competitive Intelligence</div>
342
+ <div class="section-subtitle">Pfizer vs Brand2 market dynamics across segments</div>
343
+ </div>
344
+ </div>
345
+
346
+ <div class="grid-3" style="margin-bottom:24px">
347
+ <div class="card metric-highlight">
348
+ <div class="metric-highlight-value" style="color:var(--seg-a)">3.90Γ—</div>
349
+ <div class="metric-highlight-label">Brand2/Pfizer β€” SEG_A</div>
350
+ </div>
351
+ <div class="card metric-highlight">
352
+ <div class="metric-highlight-value" style="color:var(--seg-b)">4.43Γ—</div>
353
+ <div class="metric-highlight-label">Brand2/Pfizer β€” SEG_B</div>
354
+ </div>
355
+ <div class="card metric-highlight">
356
+ <div class="metric-highlight-value" style="color:var(--seg-c)">4.29Γ—</div>
357
+ <div class="metric-highlight-label">Brand2/Pfizer β€” SEG_C</div>
358
+ </div>
359
+ </div>
360
+
361
+ <div class="alert-box alert-warning"><i class="fas fa-exclamation-triangle"></i><span><strong>Competitive
362
+ Pressure:</strong> Brand2 outprescribes Pfizer by 3.9–4.4Γ— across all segments. The gap is widest in
363
+ SEG_B (4.43Γ—), the very segment with the highest Pfizer growth trajectory β€” indicating an active
364
+ battleground for share.</span></div>
365
+
366
+ <div class="grid-2" style="margin-top:24px">
367
+ <div class="card">
368
+ <div class="chart-title">Pfizer vs Brand2: Market Share of UC (%) by Segment</div>
369
+ <div class="chart-container" style="height:300px"><canvas id="chart-comp-share"></canvas></div>
370
+ </div>
371
+ <div class="card">
372
+ <div class="chart-title">Brand2/Pfizer Prescribing Ratio by Segment</div>
373
+ <div class="chart-container" style="height:300px"><canvas id="chart-comp-ratio"></canvas></div>
374
+ </div>
375
+ </div>
376
+
377
+ <div class="card" style="margin-top:24px">
378
+ <div class="chart-title">UC TRx Volume vs Pfizer Market Share (Labeled HCPs)</div>
379
+ <div class="chart-container" style="height:420px"><canvas id="chart-scatter-uc"></canvas></div>
380
+ </div>
381
+ </div>
382
+
383
+ <!-- ==================== TAB 5: REP ENGAGEMENT ==================== -->
384
+ <div id="tab-engagement" class="tab-content">
385
+ <div class="section-header">
386
+ <div class="section-icon"><i class="fas fa-handshake"></i></div>
387
+ <div>
388
+ <div class="section-title">Rep Engagement ROI</div>
389
+ <div class="section-subtitle">Measuring commercial efficiency: visits, channels, and prescribing impact
390
+ </div>
391
+ </div>
392
+ </div>
393
+
394
+ <div class="grid-4" style="margin-bottom:24px">
395
+ <div class="card metric-highlight">
396
+ <div class="metric-highlight-value" style="color:var(--seg-a)">0.94</div>
397
+ <div class="metric-highlight-label">Details/Rx β€” SEG_A</div>
398
+ </div>
399
+ <div class="card metric-highlight">
400
+ <div class="metric-highlight-value" style="color:var(--seg-b)">0.44</div>
401
+ <div class="metric-highlight-label">Details/Rx β€” SEG_B</div>
402
+ </div>
403
+ <div class="card metric-highlight">
404
+ <div class="metric-highlight-value" style="color:var(--seg-c)">0.38</div>
405
+ <div class="metric-highlight-label">Details/Rx β€” SEG_C</div>
406
+ </div>
407
+ <div class="card metric-highlight">
408
+ <div class="metric-highlight-value" style="color:var(--accent-green)">2.1Γ—</div>
409
+ <div class="metric-highlight-label">SEG_B is 2.1Γ— more efficient than SEG_A</div>
410
+ </div>
411
+ </div>
412
+
413
+ <div class="grid-2">
414
+ <div class="card">
415
+ <div class="chart-title">Engagement Metrics by Segment</div>
416
+ <div class="chart-container" style="height:300px"><canvas id="chart-engagement"></canvas></div>
417
+ </div>
418
+ <div class="card">
419
+ <div class="chart-title">Rep Visits vs Pfizer Prescribing (Scatter)</div>
420
+ <div class="chart-container" style="height:300px"><canvas id="chart-scatter-eng"></canvas></div>
421
+ </div>
422
+ </div>
423
+ </div>
424
+
425
+ <!-- ==================== TAB 6: UNLABELED OPPORTUNITY ==================== -->
426
+ <div id="tab-opportunity" class="tab-content">
427
+ <div class="section-header">
428
+ <div class="section-icon"><i class="fas fa-crosshairs"></i></div>
429
+ <div>
430
+ <div class="section-title">Unlabeled HCP Opportunity</div>
431
+ <div class="section-subtitle">Prioritizing 633 unclassified HCPs for commercial outreach</div>
432
+ </div>
433
+ </div>
434
+
435
+ <div class="card" id="inference-card">
436
+ <div class="chart-title">Live Model Prediction: Segment Classification</div>
437
+ <div class="chart-container" style="height: auto; padding: 15px 0;">
438
+ <p style="font-size: 14px; color: var(--text-secondary); margin-bottom: 15px;">
439
+ Test the live Hugging Face model (SEG_A vs SEG_BC) with sample HCP data.
440
+ </p>
441
+ <button id="btn-predict" class="tab-btn active"
442
+ style="width: 100%; text-align: center; justify-content: center;">
443
+ <i class="fas fa-brain"></i> Run Live Prediction
444
+ </button>
445
+ <div id="prediction-result"
446
+ style="margin-top: 20px; font-weight: 600; color: var(--pfizer-deep); font-size: 16px; background: var(--bg-active); padding: 10px; border-radius: 8px; display: none;">
447
+ </div>
448
+ </div>
449
+ </div>
450
+
451
+ <div class="grid-3" style="margin-bottom:24px">
452
+ <div class="card tier-card tier-1">
453
+ <div class="tier-value" style="color:var(--accent-green)">43</div>
454
+ <div class="tier-label">Tier 1 β€” Immediate</div>
455
+ <div class="tier-desc">Score β‰₯ 0.60. Highest prescribing + growth signals.</div>
456
+ </div>
457
+ <div class="card tier-card tier-2">
458
+ <div class="tier-value" style="color:var(--accent-amber)">22</div>
459
+ <div class="tier-label">Tier 2 β€” Validate</div>
460
+ <div class="tier-desc">Score 0.35–0.60. Moderate opportunity, needs validation.</div>
461
+ </div>
462
+ <div class="card tier-card tier-3">
463
+ <div class="tier-value" style="color:var(--text-muted)">568</div>
464
+ <div class="tier-label">Tier 3 β€” Monitor</div>
465
+ <div class="tier-desc">Score < 0.35. Low activity, monitor for emergence.</div>
466
+ </div>
467
+ </div>
468
+
469
+ <div class="alert-box alert-warning"><i class="fas fa-exclamation-triangle"></i><span><strong>Coverage
470
+ Gap:</strong> 347 of 633 unlabeled HCPs (54.8%) have zero rep visits. Among Tier 1
471
+ (high-opportunity) HCPs, many prescribe actively but have never been contacted by a sales
472
+ representative.</span></div>
473
+
474
+ <div class="grid-2" style="margin-top:24px">
475
+ <div class="card">
476
+ <div class="chart-title">Opportunity Score Distribution (633 Unlabeled HCPs)</div>
477
+ <div class="chart-container" style="height:300px"><canvas id="chart-opp-hist"></canvas></div>
478
+ </div>
479
+ <div class="card">
480
+ <div class="chart-title">Click a red point to identify the HCP below ↓</div>
481
+ <div class="chart-container" style="height:300px"><canvas id="chart-opp-scatter"></canvas></div>
482
+ </div>
483
+ </div>
484
+
485
+ <!-- HCP Detail Panel (populated on click) -->
486
+ <div id="hcp-detail-panel" class="card"
487
+ style="margin-top:24px;display:none;border-left:4px solid var(--accent-coral)">
488
+ <div class="section-header" style="margin-bottom:16px">
489
+ <div class="section-icon" style="background:#fef2f2;color:var(--accent-coral)"><i
490
+ class="fas fa-user-md"></i></div>
491
+ <div>
492
+ <div class="section-title" id="hcp-detail-title">HCP Selected</div>
493
+ <div class="section-subtitle">Zero rep visits β€” high opportunity for outreach</div>
494
+ </div>
495
+ </div>
496
+ <div class="grid-5" id="hcp-detail-grid"></div>
497
+ <div class="alert-box alert-warning" style="margin-top:16px"><i
498
+ class="fas fa-bullhorn"></i><span><strong>Action Required:</strong> This HCP has never been
499
+ visited by a sales representative yet shows significant UC prescribing activity. Recommend
500
+ scheduling an initial detail call.</span></div>
501
+ </div>
502
+ </div>
503
+
504
+ <!-- ==================== TAB 7: SPECIALTY MIX ==================== -->
505
+ <div id="tab-specialty" class="tab-content">
506
+ <div class="section-header">
507
+ <div class="section-icon"><i class="fas fa-stethoscope"></i></div>
508
+ <div>
509
+ <div class="section-title">Specialty & Demographics</div>
510
+ <div class="section-subtitle">HCP specialty distribution across segments</div>
511
+ </div>
512
+ </div>
513
+
514
+ <div class="grid-2">
515
+ <div class="card">
516
+ <div class="chart-title">HCPs by Specialty and Segment (Stacked)</div>
517
+ <div class="chart-container" style="height:300px"><canvas id="chart-spec-stack"></canvas></div>
518
+ </div>
519
+ <div class="card">
520
+ <div class="chart-title">Specialty Composition (% within each specialty)</div>
521
+ <div class="chart-container" style="height:300px"><canvas id="chart-spec-pct"></canvas></div>
522
+ </div>
523
+ </div>
524
+ </div>
525
+
526
+
527
+
528
+ <script src="app.js"></script>
529
  </body>
530
+
531
+ </html>