Dobator commited on
Commit
3211546
·
verified ·
1 Parent(s): b3ab4e2

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +677 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Bioinformatics
3
- emoji: 📚
4
- colorFrom: blue
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: bioinformatics
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,677 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Bioinformatics Toolkit</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <style>
10
+ .tool-card:hover {
11
+ transform: translateY(-5px);
12
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
13
+ }
14
+ .file-upload {
15
+ border: 2px dashed #cbd5e0;
16
+ transition: all 0.3s ease;
17
+ }
18
+ .file-upload:hover {
19
+ border-color: #4f46e5;
20
+ }
21
+ .file-upload.dragover {
22
+ border-color: #4f46e5;
23
+ background-color: #f0f7ff;
24
+ }
25
+ #volcanoPlot {
26
+ width: 100%;
27
+ height: 500px;
28
+ }
29
+ .gene-item:hover {
30
+ background-color: #f3f4f6;
31
+ }
32
+ </style>
33
+ </head>
34
+ <body class="bg-gray-50 min-h-screen">
35
+ <!-- Navigation -->
36
+ <nav class="bg-indigo-600 text-white shadow-lg">
37
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
38
+ <div class="flex justify-between h-16 items-center">
39
+ <div class="flex items-center">
40
+ <div class="flex-shrink-0 flex items-center">
41
+ <svg class="h-8 w-8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
42
+ <path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5a2.5 2.5 0 00-5 0V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7 0 1.49-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5a2.5 2.5 0 000-5z" />
43
+ </svg>
44
+ <span class="ml-2 text-xl font-bold">BioTools</span>
45
+ </div>
46
+ </div>
47
+ <div>
48
+ <button id="homeBtn" class="px-3 py-2 rounded-md text-sm font-medium bg-indigo-700">Home</button>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </nav>
53
+
54
+ <!-- Main Content -->
55
+ <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
56
+ <!-- Home Page -->
57
+ <div id="homePage" class="space-y-8">
58
+ <div class="text-center">
59
+ <h1 class="text-4xl font-bold text-gray-900 mb-2">Bioinformatics Toolkit</h1>
60
+ <p class="text-xl text-gray-600">A collection of tools for biological data analysis</p>
61
+ </div>
62
+
63
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
64
+ <!-- Volcano Plot Tool Card -->
65
+ <div class="bg-white rounded-lg shadow-md overflow-hidden tool-card transition-all duration-300 cursor-pointer" id="volcanoToolCard">
66
+ <div class="p-6">
67
+ <div class="flex items-center">
68
+ <div class="flex-shrink-0 bg-indigo-100 p-3 rounded-lg">
69
+ <svg class="h-8 w-8 text-indigo-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
70
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
71
+ </svg>
72
+ </div>
73
+ <div class="ml-4">
74
+ <h3 class="text-lg font-medium text-gray-900">Volcano Plot</h3>
75
+ <p class="text-gray-500">Visualize differential gene expression</p>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+
81
+ <!-- Enrichment Tool Card -->
82
+ <div class="bg-white rounded-lg shadow-md overflow-hidden tool-card transition-all duration-300 cursor-pointer" id="enrichmentToolCard">
83
+ <div class="p-6">
84
+ <div class="flex items-center">
85
+ <div class="flex-shrink-0 bg-green-100 p-3 rounded-lg">
86
+ <svg class="h-8 w-8 text-green-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
87
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
88
+ </svg>
89
+ </div>
90
+ <div class="ml-4">
91
+ <h3 class="text-lg font-medium text-gray-900">Gene Enrichment</h3>
92
+ <p class="text-gray-500">Analyze DEGs for pathway enrichment</p>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Volcano Plot Tool -->
101
+ <div id="volcanoToolPage" class="hidden bg-white rounded-lg shadow-md p-6 space-y-6">
102
+ <div class="flex items-center">
103
+ <button id="volcanoBackBtn" class="mr-4 p-2 rounded-full hover:bg-gray-100">
104
+ <svg class="h-6 w-6 text-gray-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
105
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
106
+ </svg>
107
+ </button>
108
+ <h2 class="text-2xl font-bold text-gray-900">Volcano Plot Tool</h2>
109
+ </div>
110
+
111
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
112
+ <div class="lg:col-span-1 space-y-4">
113
+ <div class="file-upload p-8 rounded-lg text-center cursor-pointer" id="volcanoFileUpload">
114
+ <input type="file" id="volcanoFileInput" class="hidden" accept=".csv,.tsv,.txt">
115
+ <svg class="mx-auto h-12 w-12 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
116
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
117
+ </svg>
118
+ <h3 class="mt-2 text-sm font-medium text-gray-900">Upload your data</h3>
119
+ <p class="mt-1 text-sm text-gray-500">CSV, TSV or TXT file with gene expression data</p>
120
+ <p class="mt-1 text-xs text-gray-500">(symbol, log2FoldChange, padj columns required)</p>
121
+ </div>
122
+
123
+ <div class="bg-gray-50 p-4 rounded-lg">
124
+ <h3 class="text-sm font-medium text-gray-900 mb-2">Plot Settings</h3>
125
+ <div class="space-y-3">
126
+ <div>
127
+ <label for="logFCCutoff" class="block text-sm font-medium text-gray-700">logFC Cutoff</label>
128
+ <input type="number" id="logFCCutoff" value="1" step="0.1" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
129
+ </div>
130
+ <div>
131
+ <label for="pValueCutoff" class="block text-sm font-medium text-gray-700">p-value Cutoff</label>
132
+ <input type="number" id="pValueCutoff" value="0.05" step="0.01" min="0" max="1" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
133
+ </div>
134
+ <button id="generateVolcanoBtn" class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
135
+ Generate Plot
136
+ </button>
137
+ </div>
138
+ </div>
139
+ </div>
140
+
141
+ <div class="lg:col-span-2">
142
+ <div class="bg-gray-50 p-4 rounded-lg h-full">
143
+ <h3 class="text-sm font-medium text-gray-900 mb-2">Volcano Plot</h3>
144
+ <div id="volcanoPlotContainer">
145
+ <canvas id="volcanoPlot"></canvas>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Enrichment Tool -->
153
+ <div id="enrichmentToolPage" class="hidden bg-white rounded-lg shadow-md p-6 space-y-6">
154
+ <div class="flex items-center">
155
+ <button id="enrichmentBackBtn" class="mr-4 p-2 rounded-full hover:bg-gray-100">
156
+ <svg class="h-6 w-6 text-gray-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
157
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
158
+ </svg>
159
+ </button>
160
+ <h2 class="text-2xl font-bold text-gray-900">Gene Enrichment Tool</h2>
161
+ </div>
162
+
163
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
164
+ <div class="lg:col-span-1 space-y-4">
165
+ <div class="file-upload p-8 rounded-lg text-center cursor-pointer" id="enrichmentFileUpload">
166
+ <input type="file" id="enrichmentFileInput" class="hidden" accept=".csv,.tsv,.txt">
167
+ <svg class="mx-auto h-12 w-12 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
168
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
169
+ </svg>
170
+ <h3 class="mt-2 text-sm font-medium text-gray-900">Upload your DEGs</h3>
171
+ <p class="mt-1 text-sm text-gray-500">CSV, TSV or TXT file with gene list</p>
172
+ <p class="mt-1 text-xs text-gray-500">(One gene per line or GeneID column)</p>
173
+ </div>
174
+
175
+ <div class="bg-gray-50 p-4 rounded-lg">
176
+ <h3 class="text-sm font-medium text-gray-900 mb-2">Enrichment Settings</h3>
177
+ <div class="space-y-3">
178
+ <div>
179
+ <label for="databaseSelect" class="block text-sm font-medium text-gray-700">Database</label>
180
+ <select id="databaseSelect" class="mt-1 block w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm">
181
+ <option>GO Biological Process</option>
182
+ <option>GO Molecular Function</option>
183
+ <option>GO Cellular Component</option>
184
+ <option>KEGG Pathways</option>
185
+ <option>Reactome Pathways</option>
186
+ </select>
187
+ </div>
188
+ <div>
189
+ <label for="pValueEnrichCutoff" class="block text-sm font-medium text-gray-700">p-value Cutoff</label>
190
+ <input type="number" id="pValueEnrichCutoff" value="0.05" step="0.01" min="0" max="1" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
191
+ </div>
192
+ <button id="runEnrichmentBtn" class="w-full bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
193
+ Run Enrichment
194
+ </button>
195
+ </div>
196
+ </div>
197
+ </div>
198
+
199
+ <div class="lg:col-span-2">
200
+ <div class="bg-gray-50 p-4 rounded-lg h-full">
201
+ <h3 class="text-sm font-medium text-gray-900 mb-2">Enrichment Results</h3>
202
+ <div id="enrichmentResults" class="overflow-auto max-h-96">
203
+ <div class="text-center text-gray-500 py-8">
204
+ <svg class="mx-auto h-12 w-12 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
205
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
206
+ </svg>
207
+ <p class="mt-2">Upload your DEGs and run enrichment analysis to see results</p>
208
+ </div>
209
+ </div>
210
+ </div>
211
+ </div>
212
+ </div>
213
+ </div>
214
+ </main>
215
+
216
+ <script>
217
+ // DOM Elements
218
+ const homePage = document.getElementById('homePage');
219
+ const volcanoToolPage = document.getElementById('volcanoToolPage');
220
+ const enrichmentToolPage = document.getElementById('enrichmentToolPage');
221
+
222
+ const volcanoToolCard = document.getElementById('volcanoToolCard');
223
+ const enrichmentToolCard = document.getElementById('enrichmentToolCard');
224
+
225
+ const homeBtn = document.getElementById('homeBtn');
226
+ const volcanoBackBtn = document.getElementById('volcanoBackBtn');
227
+ const enrichmentBackBtn = document.getElementById('enrichmentBackBtn');
228
+
229
+ // File upload elements
230
+ const volcanoFileUpload = document.getElementById('volcanoFileUpload');
231
+ const volcanoFileInput = document.getElementById('volcanoFileInput');
232
+ const enrichmentFileUpload = document.getElementById('enrichmentFileUpload');
233
+ const enrichmentFileInput = document.getElementById('enrichmentFileInput');
234
+
235
+ // Buttons
236
+ const generateVolcanoBtn = document.getElementById('generateVolcanoBtn');
237
+ const runEnrichmentBtn = document.getElementById('runEnrichmentBtn');
238
+
239
+ // Results containers
240
+ const enrichmentResults = document.getElementById('enrichmentResults');
241
+
242
+ // Chart variables
243
+ let volcanoChart = null;
244
+ let enrichmentChart = null;
245
+
246
+ // Event Listeners
247
+ volcanoToolCard.addEventListener('click', () => {
248
+ homePage.classList.add('hidden');
249
+ volcanoToolPage.classList.remove('hidden');
250
+ enrichmentToolPage.classList.add('hidden');
251
+ });
252
+
253
+ enrichmentToolCard.addEventListener('click', () => {
254
+ homePage.classList.add('hidden');
255
+ enrichmentToolPage.classList.remove('hidden');
256
+ volcanoToolPage.classList.add('hidden');
257
+ });
258
+
259
+ homeBtn.addEventListener('click', () => {
260
+ homePage.classList.remove('hidden');
261
+ volcanoToolPage.classList.add('hidden');
262
+ enrichmentToolPage.classList.add('hidden');
263
+ });
264
+
265
+ volcanoBackBtn.addEventListener('click', () => {
266
+ homePage.classList.remove('hidden');
267
+ volcanoToolPage.classList.add('hidden');
268
+ });
269
+
270
+ enrichmentBackBtn.addEventListener('click', () => {
271
+ homePage.classList.remove('hidden');
272
+ enrichmentToolPage.classList.add('hidden');
273
+ });
274
+
275
+ // File upload handling
276
+ volcanoFileUpload.addEventListener('click', () => volcanoFileInput.click());
277
+ enrichmentFileUpload.addEventListener('click', () => enrichmentFileInput.click());
278
+
279
+ // Drag and drop for file uploads
280
+ [volcanoFileUpload, enrichmentFileUpload].forEach(uploadArea => {
281
+ uploadArea.addEventListener('dragover', (e) => {
282
+ e.preventDefault();
283
+ uploadArea.classList.add('dragover');
284
+ });
285
+
286
+ uploadArea.addEventListener('dragleave', () => {
287
+ uploadArea.classList.remove('dragover');
288
+ });
289
+
290
+ uploadArea.addEventListener('drop', (e) => {
291
+ e.preventDefault();
292
+ uploadArea.classList.remove('dragover');
293
+
294
+ const fileInput = uploadArea === volcanoFileUpload ? volcanoFileInput : enrichmentFileInput;
295
+ if (e.dataTransfer.files.length) {
296
+ fileInput.files = e.dataTransfer.files;
297
+ updateFileUploadUI(uploadArea, e.dataTransfer.files[0].name);
298
+ }
299
+ });
300
+ });
301
+
302
+ volcanoFileInput.addEventListener('change', () => {
303
+ if (volcanoFileInput.files.length) {
304
+ updateFileUploadUI(volcanoFileUpload, volcanoFileInput.files[0].name);
305
+ }
306
+ });
307
+
308
+ enrichmentFileInput.addEventListener('change', () => {
309
+ if (enrichmentFileInput.files.length) {
310
+ updateFileUploadUI(enrichmentFileUpload, enrichmentFileInput.files[0].name);
311
+ }
312
+ });
313
+
314
+ function updateFileUploadUI(uploadArea, fileName) {
315
+ uploadArea.innerHTML = `
316
+ <svg class="mx-auto h-12 w-12 text-green-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
317
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
318
+ </svg>
319
+ <h3 class="mt-2 text-sm font-medium text-gray-900">File ready</h3>
320
+ <p class="mt-1 text-sm text-gray-500">${fileName}</p>
321
+ <p class="mt-1 text-xs text-gray-500">Click to change file</p>
322
+ `;
323
+ }
324
+
325
+ // Generate Volcano Plot
326
+ generateVolcanoBtn.addEventListener('click', () => {
327
+ if (!volcanoFileInput.files.length) {
328
+ alert('Please upload a file first');
329
+ return;
330
+ }
331
+
332
+ // In a real app, you would parse the file here
333
+ // For demo purposes, we'll use mock data
334
+ const mockData = generateMockVolcanoData();
335
+ createVolcanoPlot(mockData);
336
+ });
337
+
338
+ // Run Enrichment Analysis
339
+ runEnrichmentBtn.addEventListener('click', () => {
340
+ if (!enrichmentFileInput.files.length) {
341
+ alert('Please upload a file first');
342
+ return;
343
+ }
344
+
345
+ // In a real app, you would parse the file and run enrichment
346
+ // For demo purposes, we'll use mock results
347
+ const mockResults = generateMockEnrichmentResults();
348
+ displayEnrichmentResults(mockResults);
349
+ });
350
+
351
+ // Helper functions
352
+ function generateMockVolcanoData() {
353
+ // Generate mock data for the volcano plot
354
+ const data = [];
355
+ const geneNames = ['TP53', 'BRCA1', 'EGFR', 'MYC', 'AKT1', 'PTEN', 'CDKN2A', 'RB1', 'NF1', 'APC'];
356
+
357
+ // Generate non-significant points
358
+ for (let i = 0; i < 1000; i++) {
359
+ const log2FoldChange = (Math.random() - 0.5) * 4;
360
+ const padj = Math.pow(10, -Math.random() * 5);
361
+ data.push({
362
+ symbol: i < 10 ? geneNames[i] : `Gene_${i}`,
363
+ log2FoldChange: log2FoldChange,
364
+ padj: padj
365
+ });
366
+ }
367
+
368
+ // Add significant points (more dramatic fold changes)
369
+ for (let i = 0; i < 20; i++) {
370
+ const log2FoldChange = (Math.random() > 0.5 ? 1 : -1) * (1.5 + Math.random() * 3);
371
+ const padj = Math.pow(10, -(3 + Math.random() * 4));
372
+ data.push({
373
+ symbol: `SigGene_${i}`,
374
+ log2FoldChange: log2FoldChange,
375
+ padj: padj
376
+ });
377
+ }
378
+
379
+ return data;
380
+ }
381
+
382
+ function createVolcanoPlot(data) {
383
+ const ctx = document.getElementById('volcanoPlot').getContext('2d');
384
+ const logFCCutoff = parseFloat(document.getElementById('logFCCutoff').value);
385
+ const pValueCutoff = parseFloat(document.getElementById('pValueCutoff').value);
386
+
387
+ // Prepare data for Chart.js
388
+ const plotData = {
389
+ datasets: [{
390
+ label: 'Not significant',
391
+ data: data.filter(d =>
392
+ Math.abs(d.log2FoldChange) < logFCCutoff || d.padj > pValueCutoff
393
+ ).map(d => ({
394
+ x: d.log2FoldChange,
395
+ y: -Math.log10(d.padj),
396
+ symbol: d.symbol
397
+ })),
398
+ backgroundColor: 'rgba(120, 120, 120, 0.3)',
399
+ borderColor: 'rgba(120, 120, 120, 0.5)',
400
+ borderWidth: 1,
401
+ pointRadius: 3,
402
+ pointHoverRadius: 5
403
+ }, {
404
+ label: 'Up-regulated',
405
+ data: data.filter(d =>
406
+ d.log2FoldChange >= logFCCutoff && d.padj <= pValueCutoff
407
+ ).map(d => ({
408
+ x: d.log2FoldChange,
409
+ y: -Math.log10(d.padj),
410
+ symbol: d.symbol
411
+ })),
412
+ backgroundColor: 'rgba(220, 50, 50, 0.8)',
413
+ borderColor: 'rgba(180, 40, 40, 1)',
414
+ borderWidth: 1,
415
+ pointRadius: 4,
416
+ pointHoverRadius: 6
417
+ }, {
418
+ label: 'Down-regulated',
419
+ data: data.filter(d =>
420
+ d.log2FoldChange <= -logFCCutoff && d.padj <= pValueCutoff
421
+ ).map(d => ({
422
+ x: d.log2FoldChange,
423
+ y: -Math.log10(d.padj),
424
+ symbol: d.symbol
425
+ })),
426
+ backgroundColor: 'rgba(50, 120, 220, 0.8)',
427
+ borderColor: 'rgba(40, 90, 180, 1)',
428
+ borderWidth: 1,
429
+ pointRadius: 4,
430
+ pointHoverRadius: 6
431
+ }]
432
+ };
433
+
434
+ // Destroy previous chart if it exists
435
+ if (volcanoChart) {
436
+ volcanoChart.destroy();
437
+ }
438
+
439
+ // Create new chart
440
+ volcanoChart = new Chart(ctx, {
441
+ type: 'scatter',
442
+ data: plotData,
443
+ options: {
444
+ responsive: true,
445
+ maintainAspectRatio: false,
446
+ scales: {
447
+ x: {
448
+ title: {
449
+ display: true,
450
+ text: 'log2 Fold Change (log2FC)',
451
+ font: {
452
+ weight: 'bold'
453
+ }
454
+ },
455
+ grid: {
456
+ color: 'rgba(0, 0, 0, 0.05)'
457
+ }
458
+ },
459
+ y: {
460
+ title: {
461
+ display: true,
462
+ text: '-log10(adj. p-value)',
463
+ font: {
464
+ weight: 'bold'
465
+ }
466
+ },
467
+ grid: {
468
+ color: 'rgba(0, 0, 0, 0.05)'
469
+ }
470
+ }
471
+ },
472
+ plugins: {
473
+ tooltip: {
474
+ callbacks: {
475
+ title: function(context) {
476
+ return context[0].raw.symbol;
477
+ },
478
+ label: function(context) {
479
+ return [
480
+ `log2FC: ${context.parsed.x.toFixed(2)}`,
481
+ `adj. p-value: ${Math.pow(10, -context.parsed.y).toExponential(2)}`
482
+ ];
483
+ }
484
+ }
485
+ },
486
+ legend: {
487
+ position: 'top',
488
+ }
489
+ },
490
+ onClick: (e) => {
491
+ const points = volcanoChart.getElementsAtEventForMode(
492
+ e, 'nearest', { intersect: true }, true
493
+ );
494
+ if (points.length) {
495
+ const point = points[0];
496
+ const symbol = volcanoChart.data.datasets[point.datasetIndex].data[point.index].symbol;
497
+ alert(`Selected gene: ${symbol}`);
498
+ }
499
+ }
500
+ }
501
+ });
502
+ }
503
+
504
+ function generateMockEnrichmentResults() {
505
+ const databases = [
506
+ 'GO Biological Process',
507
+ 'GO Molecular Function',
508
+ 'GO Cellular Component',
509
+ 'KEGG Pathways',
510
+ 'Reactome Pathways'
511
+ ];
512
+
513
+ const selectedDB = document.getElementById('databaseSelect').value;
514
+ const results = [];
515
+
516
+ for (let i = 1; i <= 10; i++) {
517
+ results.push({
518
+ term: `${selectedDB} term ${i}`,
519
+ pValue: (Math.random() * 0.04).toFixed(4),
520
+ genes: Math.floor(Math.random() * 50) + 5,
521
+ overlap: `${Math.floor(Math.random() * 15) + 1}/${Math.floor(Math.random() * 20) + 5}`
522
+ });
523
+ }
524
+
525
+ // Sort by p-value
526
+ return results.sort((a, b) => parseFloat(a.pValue) - parseFloat(b.pValue));
527
+ }
528
+
529
+ function displayEnrichmentResults(results) {
530
+ const pValueCutoff = parseFloat(document.getElementById('pValueEnrichCutoff').value);
531
+ const filteredResults = results.filter(r => parseFloat(r.pValue) <= pValueCutoff);
532
+
533
+ // Destroy previous chart if exists
534
+ if (enrichmentChart) {
535
+ enrichmentChart.destroy();
536
+ }
537
+
538
+ if (filteredResults.length === 0) {
539
+ document.getElementById('enrichmentResults').innerHTML = `
540
+ <div class="text-center text-gray-500 py-8">
541
+ <svg class="mx-auto h-12 w-12 text-gray-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
542
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
543
+ </svg>
544
+ <p class="mt-2">No significant enrichment results found</p>
545
+ <p class="text-sm">Try adjusting the p-value cutoff</p>
546
+ </div>
547
+ `;
548
+ return;
549
+ }
550
+
551
+ let html = `
552
+ <div class="overflow-x-auto">
553
+ <table class="min-w-full divide-y divide-gray-200">
554
+ <thead class="bg-gray-100">
555
+ <tr>
556
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Term</th>
557
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">p-value</th>
558
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Genes</th>
559
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Overlap</th>
560
+ </tr>
561
+ </thead>
562
+ <tbody class="bg-white divide-y divide-gray-200">
563
+ `;
564
+
565
+ filteredResults.forEach(result => {
566
+ const pValueColor = parseFloat(result.pValue) < 0.01 ? 'text-red-600' : 'text-yellow-600';
567
+
568
+ html += `
569
+ <tr class="hover:bg-gray-50 cursor-pointer gene-item" onclick="alert('${result.term}')">
570
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${result.term}</td>
571
+ <td class="px-6 py-4 whitespace-nowrap text-sm ${pValueColor}">${result.pValue}</td>
572
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${result.genes}</td>
573
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${result.overlap}</td>
574
+ </tr>
575
+ `;
576
+ });
577
+
578
+ html += `
579
+ </tbody>
580
+ </table>
581
+ </div>
582
+ <div class="mt-4 text-sm text-gray-500">
583
+ Showing ${filteredResults.length} of ${results.length} terms (p-value ≤ ${pValueCutoff})
584
+ </div>
585
+ `;
586
+
587
+ document.getElementById('enrichmentResults').innerHTML = html;
588
+
589
+ // Create enrichment chart if we have results
590
+ if (filteredResults.length > 0) {
591
+ const ctx = document.getElementById('enrichmentChart').getContext('2d');
592
+ const labels = filteredResults.map(r => r.term);
593
+ const pValues = filteredResults.map(r => -Math.log10(parseFloat(r.pValue)));
594
+ const geneCounts = filteredResults.map(r => r.genes);
595
+
596
+ // Sort by p-value (most significant first)
597
+ const sortedIndices = [...Array(filteredResults.length).keys()]
598
+ .sort((a, b) => pValues[b] - pValues[a]);
599
+
600
+ enrichmentChart = new Chart(ctx, {
601
+ type: 'bar',
602
+ data: {
603
+ labels: sortedIndices.map(i => labels[i]),
604
+ datasets: [{
605
+ label: '-log10(p-value)',
606
+ data: sortedIndices.map(i => pValues[i]),
607
+ backgroundColor: 'rgba(75, 192, 192, 0.6)',
608
+ borderColor: 'rgba(75, 192, 192, 1)',
609
+ borderWidth: 1,
610
+ yAxisID: 'y'
611
+ }, {
612
+ label: 'Gene Count',
613
+ data: sortedIndices.map(i => geneCounts[i]),
614
+ backgroundColor: 'rgba(153, 102, 255, 0.6)',
615
+ borderColor: 'rgba(153, 102, 255, 1)',
616
+ borderWidth: 1,
617
+ type: 'line',
618
+ yAxisID: 'y1'
619
+ }]
620
+ },
621
+ options: {
622
+ responsive: true,
623
+ plugins: {
624
+ title: {
625
+ display: true,
626
+ text: 'Enrichment Results',
627
+ font: {
628
+ size: 16
629
+ }
630
+ },
631
+ tooltip: {
632
+ callbacks: {
633
+ label: function(context) {
634
+ let label = context.dataset.label || '';
635
+ if (label) {
636
+ label += ': ';
637
+ }
638
+ if (context.datasetIndex === 0) {
639
+ label += context.raw.toFixed(2);
640
+ } else {
641
+ label += context.raw;
642
+ }
643
+ return label;
644
+ }
645
+ }
646
+ }
647
+ },
648
+ scales: {
649
+ y: {
650
+ type: 'linear',
651
+ display: true,
652
+ position: 'left',
653
+ title: {
654
+ display: true,
655
+ text: '-log10(p-value)'
656
+ }
657
+ },
658
+ y1: {
659
+ type: 'linear',
660
+ display: true,
661
+ position: 'right',
662
+ title: {
663
+ display: true,
664
+ text: 'Gene Count'
665
+ },
666
+ grid: {
667
+ drawOnChartArea: false
668
+ }
669
+ }
670
+ }
671
+ }
672
+ });
673
+ }
674
+ }
675
+ </script>
676
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Dobator/bioinformatics" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
677
+ </html>