-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdifferential-expression.html
More file actions
461 lines (417 loc) · 27.3 KB
/
differential-expression.html
File metadata and controls
461 lines (417 loc) · 27.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>scRNA-seq 聚類標誌物鑑定互動指南</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
.chart-container {
position: relative;
width: 100%;
max-width: 800px;
margin-left: auto;
margin-right: auto;
height: 400px;
max-height: 500px;
}
@media (min-width: 768px) { .chart-container { height: 450px; } }
.tab-active { border-bottom: 2px solid #0d9488; color: #0d9488; font-weight: bold; }
.fade-in { animation: fadeIn 0.3s ease-in-out; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.glass-card { background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); }
</style>
</head>
<body class="bg-slate-50 text-slate-800 min-h-screen">
<!-- Chosen Palette: Warm Neutrals with Teal and Cyan Accents (bg-slate-50, text-slate-800, teal-600 for primary actions, cyan-700 for data visualization accents). -->
<!-- Application Structure Plan: The SPA is structured as a unified dashboard with a persistent top navigation bar and dynamic content sections (Overview, Parameters & Interactive Filter, Statistical Tests, Results & Best Practices). This non-linear structure allows users to jump directly to specific aspects of marker identification. The interactive Volcano Plot serves as the core teaching tool, letting users tangibly manipulate parameters (like logfc.threshold) to see real-time filtering effects, turning abstract text into an experiential learning process. -->
<!-- Visualization & Content Choices:
1. Concept Intro -> Goal: Inform -> Method: Interactive Tab Cards -> Justification: Breaks down dense text into digestible, selectable chunks. -> Library: Vanilla JS + HTML.
2. Parameter Filtering -> Goal: Change & Explore -> Method: Interactive Scatter Plot (Volcano Plot proxy) -> Justification: Visually demonstrates how logfc and p-value thresholds isolate marker genes, directly applying the 'logfc.threshold' and 'p_val_adj' concepts. -> Library: Chart.js Canvas.
3. Statistical Tests -> Goal: Compare -> Method: Clickable list with detail panel -> Justification: Allows user to explore the pros/cons of Wilcoxon vs MAST without screen clutter. -> Library: Vanilla JS.
4. Visualizations & Best Practices -> Goal: Inform -> Method: Grid layout with Unicode icons -> Justification: Cleanly summarizes final steps and warnings. -> Library: Tailwind CSS.
Confirming NO SVG/Mermaid used. -->
<!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. -->
<nav class="bg-white shadow-md sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<span class="text-2xl font-extrabold text-teal-600 tracking-tight">☄ scRNA-seq 分析指南</span>
</div>
<div class="hidden md:flex space-x-8 items-center" id="nav-links">
<button onclick="switchSection('section-intro')" class="nav-btn text-gray-600 hover:text-teal-600 font-medium px-3 py-2 tab-active" data-target="section-intro">核心概念</button>
<button onclick="switchSection('section-params')" class="nav-btn text-gray-600 hover:text-teal-600 font-medium px-3 py-2" data-target="section-params">參數與互動過濾</button>
<button onclick="switchSection('section-stats')" class="nav-btn text-gray-600 hover:text-teal-600 font-medium px-3 py-2" data-target="section-stats">統計檢定</button>
<button onclick="switchSection('section-results')" class="nav-btn text-gray-600 hover:text-teal-600 font-medium px-3 py-2" data-target="section-results">結果解讀與建議</button>
</div>
</div>
</div>
</nav>
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<section id="section-intro" class="content-section fade-in block">
<div class="mb-8">
<h1 class="text-4xl font-bold text-slate-900 mb-4">尋找差異表達特徵 (Cluster Biomarkers)</h1>
<p class="text-lg text-slate-600 leading-relaxed bg-white p-6 rounded-xl shadow-sm border border-slate-100">
本區塊介紹單細胞數據分析中差異表達 (DE) 的基礎。在完成細胞分群後,我們必須找出定義各群的「標誌基因」。理想的標誌物需要具備高靈敏度與高特異性。點擊下方卡片探索不同的比較策略與主流軟體函數。
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-10">
<div class="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden hover:shadow-md transition-shadow">
<div class="bg-teal-50 border-b border-teal-100 px-6 py-4">
<h2 class="text-xl font-bold text-teal-800">➚ 比較策略 (DE Strategies)</h2>
</div>
<div class="p-6">
<div class="mb-4">
<h3 class="font-bold text-lg text-slate-800 mb-2">一對多 (One vs. All)</h3>
<p class="text-slate-600">將特定聚類與剩餘的「所有細胞」進行比較。目標是找出該群**專有**的特徵,通常用於定義大類型的細胞。</p>
</div>
<div class="w-full h-px bg-slate-200 my-4"></div>
<div>
<h3 class="font-bold text-lg text-slate-800 mb-2">一對一 (One vs. One)</h3>
<p class="text-slate-600">比較兩個特定的聚類 (如 Cluster A vs B)。通常用於區分非常相似的亞群 (Subtypes),尋找細微的特徵差異。</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden hover:shadow-md transition-shadow">
<div class="bg-cyan-50 border-b border-cyan-100 px-6 py-4">
<h2 class="text-xl font-bold text-cyan-800">⚙ 核心工具 (Seurat 函數)</h2>
</div>
<div class="p-6">
<p class="text-slate-600 mb-6">目前主流使用 R 工具包 Seurat 進行標誌物鑑定。</p>
<ul class="space-y-4">
<li class="flex items-start">
<span class="bg-cyan-100 text-cyan-800 font-mono text-sm px-2 py-1 rounded mr-3 mt-1 shadow-sm">FindMarkers()</span>
<div>
<p class="text-slate-700">用於**手動指定**兩群或多群細胞進行比較。</p>
</div>
</li>
<li class="flex items-start">
<span class="bg-cyan-100 text-cyan-800 font-mono text-sm px-2 py-1 rounded mr-3 mt-1 shadow-sm">FindAllMarkers()</span>
<div>
<p class="text-slate-700">**自動遍歷**所有聚類,將每一群分別與其餘細胞進行比較。這是初步細胞類型鑑定最常用的函數。</p>
</div>
</li>
</ul>
</div>
</div>
</div>
</section>
<section id="section-params" class="content-section fade-in hidden">
<div class="mb-8">
<h2 class="text-3xl font-bold text-slate-900 mb-4">關鍵篩選參數與互動模擬</h2>
<p class="text-lg text-slate-600 bg-white p-6 rounded-xl shadow-sm border border-slate-100">
設定適當的門檻 (Thresholds) 可以過濾技術雜訊並加速運算。本區塊透過模擬基因數據,讓您親自調整 <code>logfc.threshold</code> 與 <code>p-value</code> 門檻,觀察標誌基因如何從背景雜訊中被分離出來。
</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
<div class="col-span-1 bg-white p-6 rounded-xl shadow-sm border border-slate-200">
<h3 class="font-bold text-xl text-slate-800 mb-6 border-b pb-2">參數控制面板</h3>
<div class="mb-6">
<label class="block text-sm font-bold text-slate-700 mb-2">
logfc.threshold: <span id="logfc-display" class="text-teal-600">0.25</span>
</label>
<p class="text-xs text-slate-500 mb-2">平均表現量對數差異 (log2FC)。預設 0.25。拉動滑桿觀察圖表變化。</p>
<input type="range" id="logfc-slider" min="0" max="2" step="0.05" value="0.25" class="w-full accent-teal-600" oninput="updateChartDisplay()">
</div>
<div class="mb-6">
<label class="block text-sm font-bold text-slate-700 mb-2">
p_val_adj 顯著性門檻: <span id="pval-display" class="text-teal-600">0.05</span>
</label>
<p class="text-xs text-slate-500 mb-2">校正後的 P 值。需小於此門檻才視為顯著。</p>
<input type="range" id="pval-slider" min="0.001" max="0.1" step="0.005" value="0.05" class="w-full accent-teal-600" oninput="updateChartDisplay()">
</div>
<div class="mb-6 bg-slate-50 p-4 rounded-lg border border-slate-200">
<h4 class="font-bold text-sm text-slate-800 mb-2">其他重要參數 (靜態說明)</h4>
<ul class="text-sm space-y-2 text-slate-600">
<li><strong><code class="text-teal-700">min.pct</code></strong>: 基因必須在至少 X% 的細胞中被偵測到 (過濾少數表現基因)。</li>
<li><strong><code class="text-teal-700">only.pos</code></strong>: 若為 TRUE,僅保留「上調」的高表現基因。</li>
</ul>
</div>
</div>
<div class="col-span-1 lg:col-span-2 bg-white p-6 rounded-xl shadow-sm border border-slate-200">
<h3 class="font-bold text-xl text-slate-800 mb-2">差異表達模擬散佈圖 (Volcano Plot Proxy)</h3>
<p class="text-sm text-slate-500 mb-4">X 軸為 Log2 Fold Change,Y 軸為 -Log10(P-value)。紅色/青色點為符合您左側門檻設定的顯著標誌基因。</p>
<div class="chart-container">
<canvas id="volcanoChart"></canvas>
</div>
<div class="mt-4 flex justify-center space-x-6 text-sm">
<span class="flex items-center"><span class="w-3 h-3 rounded-full bg-teal-500 mr-2"></span> 目標群高表現標誌基因</span>
<span class="flex items-center"><span class="w-3 h-3 rounded-full bg-slate-300 mr-2"></span> 未達顯著門檻基因</span>
</div>
</div>
</div>
</section>
<section id="section-stats" class="content-section fade-in hidden">
<div class="mb-8">
<h2 class="text-3xl font-bold text-slate-900 mb-4">統計檢定方法 (Statistical Tests)</h2>
<p class="text-lg text-slate-600 bg-white p-6 rounded-xl shadow-sm border border-slate-100">
scRNA-seq 數據具有高度稀疏性 (Sparse) 與 Dropout 現象。選擇正確的 <code>test.use</code> 模型對分析準確度至關重要。點擊下方列表探索不同的統計模型。
</p>
</div>
<div class="flex flex-col md:flex-row gap-6">
<div class="w-full md:w-1/3 flex flex-col space-y-3">
<button onclick="showTestDetails('wilcoxon')" id="btn-wilcoxon" class="test-btn text-left p-4 rounded-lg border-2 border-teal-500 bg-teal-50 font-bold text-teal-900 transition-all">
Wilcoxon Rank Sum Test
</button>
<button onclick="showTestDetails('mast')" id="btn-mast" class="test-btn text-left p-4 rounded-lg border-2 border-transparent bg-white hover:bg-slate-50 font-bold text-slate-700 transition-all">
MAST
</button>
<button onclick="showTestDetails('deseq')" id="btn-deseq" class="test-btn text-left p-4 rounded-lg border-2 border-transparent bg-white hover:bg-slate-50 font-bold text-slate-700 transition-all">
DESeq2 / edgeR (Pseudo-bulk)
</button>
<button onclick="showTestDetails('roc')" id="btn-roc" class="test-btn text-left p-4 rounded-lg border-2 border-transparent bg-white hover:bg-slate-50 font-bold text-slate-700 transition-all">
ROC Analysis
</button>
</div>
<div class="w-full md:w-2/3 bg-white p-8 rounded-xl shadow-sm border border-slate-200 min-h-[300px]" id="test-details-container">
<h3 id="test-title" class="text-2xl font-bold text-slate-800 mb-4 pb-2 border-b border-slate-200">Wilcoxon Rank Sum Test (預設)</h3>
<div class="mb-4">
<span class="inline-block bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm font-bold mb-3">優點</span>
<p id="test-pros" class="text-slate-700 leading-relaxed">非參數檢定,對數據分布不作假設,運算速度極快,且在多項基準測試中表現優異。</p>
</div>
<div>
<span class="inline-block bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm font-bold mb-3">適用場景</span>
<p id="test-usecase" class="text-slate-700 leading-relaxed">絕大多數通用場景,是最穩定且推薦的預設起點。</p>
</div>
</div>
</div>
</section>
<section id="section-results" class="content-section fade-in hidden">
<div class="mb-8">
<h2 class="text-3xl font-bold text-slate-900 mb-4">結果解讀與可視化</h2>
<p class="text-lg text-slate-600 bg-white p-6 rounded-xl shadow-sm border border-slate-100">
算出結果矩陣後,真正的挑戰在於生物學解讀。本區解釋表格中的關鍵指標,並列出常用的視覺化驗證方法與最佳實踐建議。
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-200 border-t-4 border-t-cyan-600">
<h3 class="font-bold text-xl text-slate-800 mb-4 flex items-center">✔ 解讀數據表格</h3>
<ul class="space-y-4">
<li class="bg-slate-50 p-3 rounded border border-slate-100">
<strong class="text-cyan-800 block mb-1">p_val_adj</strong>
<p class="text-sm text-slate-600">校正後的 p 值 (Bonferroni 或 FDR)。通常 < 0.05 視為統計上顯著。</p>
</li>
<li class="bg-slate-50 p-3 rounded border border-slate-100">
<strong class="text-cyan-800 block mb-1">avg_log2FC</strong>
<p class="text-sm text-slate-600">表現量差異的對數倍數。正值代表在目標群中高表現。數值越大特異性越強。</p>
</li>
<li class="bg-slate-50 p-3 rounded border border-slate-100">
<strong class="text-cyan-800 block mb-1">pct.1 / pct.2</strong>
<p class="text-sm text-slate-600">基因在目標群 (pct.1) 與對照群 (pct.2) 中表達細胞的比例。理想標誌物 pct.1 高且 pct.2 低。</p>
</li>
</ul>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-200 border-t-4 border-t-teal-600">
<h3 class="font-bold text-xl text-slate-800 mb-4 flex items-center">⚏ 驗證圖表 (可視化方式)</h3>
<div class="grid grid-cols-2 gap-4">
<div class="bg-teal-50 p-3 rounded text-center">
<div class="text-2xl mb-2 text-teal-700">⁂</div>
<strong class="block text-sm text-slate-800">VlnPlot</strong>
<span class="text-xs text-slate-500">觀察表達分布強度</span>
</div>
<div class="bg-teal-50 p-3 rounded text-center">
<div class="text-2xl mb-2 text-teal-700">⊙</div>
<strong class="block text-sm text-slate-800">FeaturePlot</strong>
<span class="text-xs text-slate-500">UMAP 空間特異性</span>
</div>
<div class="bg-teal-50 p-3 rounded text-center">
<div class="text-2xl mb-2 text-teal-700">⊛</div>
<strong class="block text-sm text-slate-800">DotPlot</strong>
<span class="text-xs text-slate-500">表達比例與強度結合</span>
</div>
<div class="bg-teal-50 p-3 rounded text-center">
<div class="text-2xl mb-2 text-teal-700">▦</div>
<strong class="block text-sm text-slate-800">DoHeatmap</strong>
<span class="text-xs text-slate-500">Top markers 表達矩陣</span>
</div>
</div>
</div>
</div>
<div class="bg-gradient-to-r from-slate-800 to-slate-900 rounded-xl p-8 text-white shadow-lg">
<h3 class="font-bold text-2xl mb-6 flex items-center text-teal-400">★ 最佳實踐建議</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<h4 class="font-bold text-lg mb-2 text-white">1. 不要過度依賴 p 值</h4>
<p class="text-slate-300 text-sm">單細胞分析中細胞數量極大,微小差異也會產生極顯著的 p 值。務必結合 log2FC 與 pct 差異判斷生物學意義。</p>
</div>
<div>
<h4 class="font-bold text-lg mb-2 text-white">2. 嚴格驗證 pct 差異</h4>
<p class="text-slate-300 text-sm">優質標誌基因應在目標群有高表達率 (如 >70%),在其他群表達率極低 (如 <20%)。</p>
</div>
<div>
<h4 class="font-bold text-lg mb-2 text-white">3. 結合先驗知識</h4>
<p class="text-slate-300 text-sm">生信分析只是輔助,最終鑑定需比對 CellMarker、PanglaoDB 等資料庫或文獻,確認基因符合已知細胞特徵。</p>
</div>
</div>
</div>
</section>
</main>
<script>
// Navigation Logic
function switchSection(targetId) {
const sections = document.querySelectorAll('.content-section');
const btns = document.querySelectorAll('.nav-btn');
sections.forEach(sec => sec.classList.add('hidden'));
btns.forEach(btn => {
btn.classList.remove('tab-active');
btn.classList.remove('border-teal-500');
});
document.getElementById(targetId).classList.remove('hidden');
const activeBtn = document.querySelector(`[data-target="${targetId}"]`);
activeBtn.classList.add('tab-active');
if(targetId === 'section-params' && volcanoChart) {
volcanoChart.resize();
}
}
// Statistical Tests Data
const testData = {
wilcoxon: {
title: "Wilcoxon Rank Sum Test (預設)",
pros: "非參數檢定,對數據分布不作假設,運算速度極快,且在多項基準測試中表現優異。",
usecase: "大多數通用場景,是最穩定且推薦的預設起點。"
},
mast: {
title: "MAST (Model-based Analysis)",
pros: "專為單細胞數據設計的「障礙模型」(Hurdle model),考慮了基因表達的二元性(Dropout 表現或不表現)與連續性強度。",
usecase: "想要更精確地處理技術噪音,或細胞異質性極高時。"
},
deseq: {
title: "DESeq2 / edgeR (Pseudo-bulk)",
pros: "將單細胞數據按生物樣本聚合後進行分析,能有效控制生物學重複間的變異。",
usecase: "當實驗包含多個生物學重複(Replicates)且需比較不同條件(如處理組 vs 對照組)時。"
},
roc: {
title: "ROC (Receiver Operating Characteristic)",
pros: "計算每個基因分類該群細胞的能力 (AUC 值),結果不受細胞數量多寡的影響。",
usecase: "尋找具備極高分類預測能力的絕對標誌基因時。"
}
};
function showTestDetails(testId) {
document.querySelectorAll('.test-btn').forEach(btn => {
btn.classList.remove('border-teal-500', 'bg-teal-50', 'text-teal-900');
btn.classList.add('border-transparent', 'bg-white', 'text-slate-700');
});
const activeBtn = document.getElementById(`btn-${testId}`);
activeBtn.classList.remove('border-transparent', 'bg-white', 'text-slate-700');
activeBtn.classList.add('border-teal-500', 'bg-teal-50', 'text-teal-900');
const data = testData[testId];
document.getElementById('test-title').innerText = data.title;
document.getElementById('test-pros').innerText = data.pros;
document.getElementById('test-usecase').innerText = data.usecase;
const container = document.getElementById('test-details-container');
container.classList.remove('fade-in');
void container.offsetWidth;
container.classList.add('fade-in');
}
// Chart.js Volcano Plot Logic
let volcanoChart = null;
let geneData = [];
function generateMockData() {
geneData = [];
for (let i = 0; i < 200; i++) {
let log2fc = (Math.random() - 0.5) * 6;
let pvalRaw = Math.pow(10, -(Math.random() * 10));
let minusLog10P = -Math.log10(pvalRaw);
// Add some artificial correlation for realistic volcano look
if (Math.abs(log2fc) > 1.5) {
minusLog10P += Math.random() * 5 + 2;
}
geneData.push({
x: log2fc,
y: minusLog10P,
rawPval: pvalRaw,
name: `Gene_${i+1}`
});
}
}
function initChart() {
generateMockData();
const ctx = document.getElementById('volcanoChart').getContext('2d');
volcanoChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: '顯著標誌基因',
data: [],
backgroundColor: '#0d9488',
pointRadius: 5,
pointHoverRadius: 8
}, {
label: '非顯著基因 (雜訊)',
data: [],
backgroundColor: '#cbd5e1',
pointRadius: 3,
pointHoverRadius: 5
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'top' },
tooltip: {
callbacks: {
label: function(context) {
const point = context.raw;
return `${point.name} | Log2FC: ${point.x.toFixed(2)} | P-val: ${point.rawPval.toExponential(2)}`;
}
}
}
},
scales: {
x: {
title: { display: true, text: 'Log2 Fold Change (avg_log2FC)', font: {weight: 'bold'} },
grid: { color: '#f1f5f9' }
},
y: {
title: { display: true, text: '-Log10(p_val_adj)', font: {weight: 'bold'} },
grid: { color: '#f1f5f9' },
min: 0
}
},
animation: { duration: 400 }
}
});
updateChartDisplay();
}
function updateChartDisplay() {
const logfcThresh = parseFloat(document.getElementById('logfc-slider').value);
const pvalThreshRaw = parseFloat(document.getElementById('pval-slider').value);
const pvalThreshMinusLog10 = -Math.log10(pvalThreshRaw);
document.getElementById('logfc-display').innerText = logfcThresh.toFixed(2);
document.getElementById('pval-display').innerText = pvalThreshRaw.toFixed(3);
let significantData = [];
let nonSignificantData = [];
geneData.forEach(gene => {
// To match strictly target cluster markers (positive logFC usually preferred, but we show both ends)
// However, guide mentions only.pos. We will highlight just positive logFC if it meets threshold, or absolute for generic.
// Let's highlight absolute to show standard volcano behavior, but color right side teal, left side cyan for distinction.
let isSig = Math.abs(gene.x) >= logfcThresh && gene.y >= pvalThreshMinusLog10;
if (isSig) {
// For simplicity, grouping all significant into dataset 0
significantData.push(gene);
} else {
nonSignificantData.push(gene);
}
});
volcanoChart.data.datasets[0].data = significantData;
volcanoChart.data.datasets[1].data = nonSignificantData;
// Add reference lines via standard chart update
volcanoChart.options.plugins.annotation = {
annotations: {
line1: { type: 'line', yMin: pvalThreshMinusLog10, yMax: pvalThreshMinusLog10, borderColor: 'red', borderWidth: 1, borderDash: [5, 5] },
line2: { type: 'line', xMin: logfcThresh, xMax: logfcThresh, borderColor: 'red', borderWidth: 1, borderDash: [5, 5] },
line3: { type: 'line', xMin: -logfcThresh, xMax: -logfcThresh, borderColor: 'red', borderWidth: 1, borderDash: [5, 5] }
}
};
volcanoChart.update();
}
// Initialize on load
window.addEventListener('DOMContentLoaded', () => {
initChart();
});
</script>
</body>
</html>