Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>scAnalyzer Studio</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
| </head> | |
| <body class="bg-gray-900 text-gray-100 font-sans min-h-screen pb-12"> | |
| <div class="max-w-7xl mx-auto py-12 px-6"> | |
| <div class="text-center mb-12"> | |
| <h1 class="text-5xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-teal-400 to-indigo-500 mb-4"> | |
| <i class="fas fa-network-wired mr-2 text-teal-400"></i> scAnalyzer Studio | |
| </h1> | |
| <p class="text-gray-400 text-lg">Full single-cell RNA-seq pipeline.</p> | |
| </div> | |
| <form id="pipelineForm" class="space-y-6"> | |
| <div class="bg-gray-800 p-6 rounded-xl shadow-lg border border-gray-700"> | |
| <h2 class="text-xl font-semibold mb-4 text-teal-300"><i class="fas fa-database mr-2"></i> 1. Dataset</h2> | |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4"> | |
| {% for ds in datasets %} | |
| <label class="flex items-center space-x-2 p-3 border border-gray-600 rounded cursor-pointer hover:bg-gray-700 transition"> | |
| <input type="radio" name="dataset" value="{{ ds }}" class="form-radio text-teal-500 h-4 w-4" required> | |
| <span class="text-gray-200 text-sm capitalize">{{ ds | replace('_', ' ') }}</span> | |
| </label> | |
| {% endfor %} | |
| <label class="flex items-center space-x-2 p-3 border border-teal-600 rounded cursor-pointer bg-teal-900 bg-opacity-20 hover:bg-opacity-40 transition"> | |
| <input type="radio" name="dataset" value="custom" id="customRadio" class="form-radio text-teal-500 h-4 w-4"> | |
| <span class="text-teal-300 text-sm font-bold">Custom Upload</span> | |
| </label> | |
| </div> | |
| <input type="file" name="custom_file" id="customFile" class="hidden w-full text-sm text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:bg-teal-600 file:text-white hover:file:bg-teal-700"/> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> | |
| <div class="bg-gray-800 p-5 rounded-xl shadow-lg border border-gray-700"> | |
| <h2 class="text-lg font-semibold mb-3 text-purple-300"><i class="fas fa-filter mr-2"></i> Quality Control</h2> | |
| <label class="block text-xs text-gray-400 mb-1">Min Genes & Max Genes</label> | |
| <div class="flex space-x-2 mb-3"> | |
| <input type="number" name="min_genes" value="200" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm focus:border-purple-500"> | |
| <input type="number" name="max_genes" value="2500" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm focus:border-purple-500"> | |
| </div> | |
| <label class="block text-xs text-gray-400 mb-1">Max Mito % & Min Cells</label> | |
| <div class="flex space-x-2 mb-3"> | |
| <input type="number" step="0.1" name="max_mito" value="5.0" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm focus:border-purple-500"> | |
| <input type="number" name="min_cells" value="3" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm focus:border-purple-500"> | |
| </div> | |
| <label class="flex items-center space-x-2 mt-4"> | |
| <input type="checkbox" name="run_scrublet" value="true" checked class="form-checkbox text-purple-500"> | |
| <span class="text-sm text-gray-300">Run Scrublet</span> | |
| </label> | |
| <input type="number" step="0.01" name="doublet_rate" value="0.06" placeholder="Rate (0.06)" class="mt-1 w-full bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm"> | |
| </div> | |
| <div class="bg-gray-800 p-5 rounded-xl shadow-lg border border-gray-700"> | |
| <h2 class="text-lg font-semibold mb-3 text-yellow-300"><i class="fas fa-layer-group mr-2"></i> Norm & Integration</h2> | |
| <label class="block text-xs text-gray-400 mb-1">Normalization</label> | |
| <select name="norm_method" class="w-full bg-gray-700 border border-gray-600 rounded px-2 py-1 mb-3 text-sm"> | |
| <option value="total">Total Count (Log1p)</option> | |
| <option value="scran">Scran Pooling</option> | |
| <option value="sctransform">SCTransform</option> | |
| </select> | |
| <hr class="border-gray-700 my-3"> | |
| <label class="flex items-center space-x-2 mb-1"> | |
| <input type="checkbox" name="run_imputation" value="true" class="form-checkbox text-yellow-500"> | |
| <span class="text-sm text-gray-300 font-bold">Imputation</span> | |
| </label> | |
| <select name="imp_method" class="w-full bg-gray-700 border border-gray-600 rounded px-2 py-1 mb-2 text-xs"> | |
| <option value="wnid">WNID (Weighted Neighborhood)</option> | |
| <option value="knn">kNN Smooth</option> | |
| <option value="diffusion">Diffusion (t=3)</option> | |
| </select> | |
| <div class="grid grid-cols-3 gap-2 mb-3"> | |
| <div> | |
| <label class="block text-[10px] text-gray-400 mb-1">k (Neighbors)</label> | |
| <input type="number" name="imp_k" value="7" class="w-full bg-gray-700 border border-gray-600 rounded px-1 py-1 text-xs"> | |
| </div> | |
| <div> | |
| <label class="block text-[10px] text-gray-400 mb-1">Threshold</label> | |
| <input type="number" step="0.01" name="imp_thresh" value="0.72" class="w-full bg-gray-700 border border-gray-600 rounded px-1 py-1 text-xs"> | |
| </div> | |
| <div> | |
| <label class="block text-[10px] text-gray-400 mb-1">n_pcs</label> | |
| <input type="number" name="imp_pcs" value="30" class="w-full bg-gray-700 border border-gray-600 rounded px-1 py-1 text-xs"> | |
| </div> | |
| </div> | |
| <hr class="border-gray-700 my-3"> | |
| <label class="flex items-center space-x-2 mb-1"> | |
| <input type="checkbox" name="run_batch" value="true" class="form-checkbox text-yellow-500"> | |
| <span class="text-sm text-gray-300">Batch Correction</span> | |
| </label> | |
| <div class="flex space-x-2"> | |
| <select name="batch_algo" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-xs"> | |
| <option value="harmony">Harmony</option> | |
| <option value="combat">ComBat</option> | |
| <option value="mnn">MNN</option> | |
| </select> | |
| <input type="text" name="batch_key" placeholder="Col Name" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-xs"> | |
| </div> | |
| </div> | |
| <div class="bg-gray-800 p-5 rounded-xl shadow-lg border border-gray-700"> | |
| <h2 class="text-lg font-semibold mb-3 text-blue-300"><i class="fas fa-project-diagram mr-2"></i> DimRed & Networks</h2> | |
| <div class="grid grid-cols-2 gap-2 mb-3"> | |
| <div> | |
| <label class="block text-xs text-gray-400 mb-1">PCA Comps</label> | |
| <input type="number" name="n_pcs" value="50" class="w-full bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm"> | |
| </div> | |
| <div> | |
| <label class="block text-xs text-gray-400 mb-1">Neighbors (K)</label> | |
| <input type="number" name="n_neighbors" value="15" class="w-full bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm"> | |
| </div> | |
| </div> | |
| <div class="space-y-2 mt-4 mb-4"> | |
| <label class="flex items-center justify-between"> | |
| <div class="flex items-center space-x-2"> | |
| <input type="checkbox" name="run_umap" value="true" checked class="form-checkbox text-blue-500"> | |
| <span class="text-sm text-gray-300">UMAP</span> | |
| </div> | |
| <input type="number" step="0.1" name="umap_min_dist" value="0.5" class="w-16 bg-gray-700 border border-gray-600 rounded px-1 py-0.5 text-xs text-center" title="Min Dist"> | |
| </label> | |
| <label class="flex items-center justify-between"> | |
| <div class="flex items-center space-x-2"> | |
| <input type="checkbox" name="run_tsne" value="true" class="form-checkbox text-blue-500"> | |
| <span class="text-sm text-gray-300">t-SNE</span> | |
| </div> | |
| <input type="number" step="0.1" name="tsne_perplex" value="30" class="w-16 bg-gray-700 border border-gray-600 rounded px-1 py-0.5 text-xs text-center" title="Perplexity"> | |
| </label> | |
| </div> | |
| <hr class="border-gray-700 my-3"> | |
| <label class="flex items-center space-x-2 mb-1"> | |
| <input type="checkbox" name="run_grn" value="true" class="form-checkbox text-blue-500"> | |
| <span class="text-sm text-gray-300 font-bold">GRN Inference</span> | |
| </label> | |
| <label class="block text-[10px] text-gray-400 mb-1">Transcription Factors (Comma Separated)</label> | |
| <input type="text" name="tf_list" placeholder="e.g., FOXO1, MYC, TP53" value="JUN, FOS, CEBPB, SPI1" class="w-full bg-gray-700 border border-gray-600 rounded px-2 py-1 text-xs"> | |
| </div> | |
| <div class="bg-gray-800 p-5 rounded-xl shadow-lg border border-gray-700"> | |
| <h2 class="text-lg font-semibold mb-3 text-pink-300"><i class="fas fa-chart-pie mr-2"></i> Analytics</h2> | |
| <label class="block text-xs text-gray-400 mb-1">Clustering & Res/K</label> | |
| <div class="flex space-x-2 mb-3"> | |
| <select name="clustering" class="w-2/3 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-xs"> | |
| <option value="leiden">Leiden</option> | |
| <option value="louvain">Louvain</option> | |
| <option value="kmeans">K-Means</option> | |
| <option value="hierarchical">Hierarchical</option> | |
| <option value="spectral">Spectral</option> | |
| </select> | |
| <input type="number" step="0.1" name="resolution" value="1.0" class="w-1/3 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-sm text-center"> | |
| </div> | |
| <label class="block text-xs text-gray-400 mb-1">Trajectory (Root & Branches)</label> | |
| <div class="flex space-x-2 mb-3"> | |
| <select name="root_strategy" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-xs"> | |
| <option value="extreme">Extreme</option> | |
| <option value="medoid">Medoid</option> | |
| </select> | |
| <input type="number" name="branches" value="0" placeholder="Branches" class="w-1/2 bg-gray-700 border border-gray-600 rounded px-2 py-1 text-xs"> | |
| </div> | |
| <hr class="border-gray-700 my-3"> | |
| <label class="block mb-2 text-sm text-gray-300 font-bold">Interactive HTML Plots:</label> | |
| <div class="space-y-1 grid grid-cols-2 gap-1"> | |
| <label class="flex items-center space-x-2"> | |
| <input type="checkbox" name="int_umap" value="true" checked class="form-checkbox text-pink-500 h-3 w-3"> | |
| <span class="text-[10px] text-gray-300">2D UMAP</span> | |
| </label> | |
| <label class="flex items-center space-x-2"> | |
| <input type="checkbox" name="int_3d_pca" value="true" checked class="form-checkbox text-pink-500 h-3 w-3"> | |
| <span class="text-[10px] text-gray-300">3D PCA</span> | |
| </label> | |
| <label class="flex items-center space-x-2"> | |
| <input type="checkbox" name="int_tsne" value="true" class="form-checkbox text-pink-500 h-3 w-3"> | |
| <span class="text-[10px] text-gray-300">t-SNE</span> | |
| </label> | |
| <label class="flex items-center space-x-2"> | |
| <input type="checkbox" name="int_violin" value="true" checked class="form-checkbox text-pink-500 h-3 w-3"> | |
| <span class="text-[10px] text-gray-300">Violins</span> | |
| </label> | |
| <label class="flex items-center space-x-2"> | |
| <input type="checkbox" name="int_heatmap" value="true" checked class="form-checkbox text-pink-500 h-3 w-3"> | |
| <span class="text-[10px] text-gray-300">Heatmap</span> | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| <button type="submit" class="w-full bg-gradient-to-r from-teal-600 to-indigo-600 hover:from-teal-500 hover:to-indigo-500 text-white font-bold py-4 rounded-xl shadow-lg transform transition hover:scale-[1.01] text-xl"> | |
| <i class="fas fa-play mr-2"></i> Execute Analysis | |
| </button> | |
| </form> | |
| <div id="statusArea" class="hidden mt-10 bg-gray-800 p-8 rounded-xl shadow-lg border border-gray-700"> | |
| <div id="loader" class="text-center py-8"> | |
| <i class="fas fa-circle-notch fa-spin text-5xl text-teal-500 mb-4"></i> | |
| <p class="text-xl text-gray-200 font-semibold blink">Processing single-cell pipeline...</p> | |
| <p class="text-gray-400 mt-2 text-sm">Keep an eye on your terminal. Large datasets will take time.</p> | |
| </div> | |
| <div id="results" class="hidden"> | |
| <div class="flex justify-between items-center mb-6 border-b border-gray-700 pb-4"> | |
| <h2 class="text-2xl font-bold text-green-400"><i class="fas fa-check-circle mr-2"></i> Success</h2> | |
| <a id="downloadBtn" href="#" class="bg-green-600 hover:bg-green-500 text-white font-bold py-2 px-4 rounded shadow transition"> | |
| <i class="fas fa-download mr-2"></i> Download .h5ad | |
| </a> | |
| </div> | |
| <div id="interactiveContainer" class="flex flex-wrap gap-3 mb-6"></div> | |
| <div id="plotContainer" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.getElementById('customRadio').addEventListener('change', function() { | |
| document.getElementById('customFile').classList.remove('hidden'); | |
| }); | |
| document.querySelectorAll('input[name="dataset"]:not(#customRadio)').forEach(el => { | |
| el.addEventListener('change', () => document.getElementById('customFile').classList.add('hidden')); | |
| }); | |
| document.getElementById('pipelineForm').addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| document.getElementById('statusArea').classList.remove('hidden'); | |
| document.getElementById('loader').classList.remove('hidden'); | |
| document.getElementById('results').classList.add('hidden'); | |
| document.getElementById('plotContainer').innerHTML = ''; | |
| document.getElementById('interactiveContainer').innerHTML = ''; | |
| const formData = new FormData(e.target); | |
| try { | |
| const response = await fetch('/run_pipeline', { method: 'POST', body: formData }); | |
| if (!response.ok) { | |
| document.getElementById('loader').classList.add('hidden'); | |
| alert("SERVER ERROR 500: Check the terminal running Python. Something crashed inside scAnalyzer."); | |
| return; | |
| } | |
| const data = await response.json(); | |
| document.getElementById('loader').classList.add('hidden'); | |
| if (data.status === 'success') { | |
| document.getElementById('results').classList.remove('hidden'); | |
| document.getElementById('downloadBtn').href = data.download; | |
| data.outputs.forEach(out => { | |
| if (out.type === 'image') { | |
| document.getElementById('plotContainer').innerHTML += ` | |
| <div class="bg-gray-900 rounded p-3 border border-gray-700 flex flex-col items-center"> | |
| <h3 class="text-gray-300 text-sm font-semibold mb-2">${out.title}</h3> | |
| <a href="${out.url}" target="_blank"> | |
| <img src="${out.url}?t=${new Date().getTime()}" class="rounded hover:opacity-80 transition object-contain max-h-56"> | |
| </a> | |
| </div> | |
| `; | |
| } else if (out.type === 'html') { | |
| document.getElementById('interactiveContainer').innerHTML += ` | |
| <a href="${out.url}" target="_blank" class="flex-1 bg-gray-700 hover:bg-gray-600 text-pink-300 text-sm font-medium py-2 px-3 rounded shadow border border-gray-600 text-center transition"> | |
| <i class="fas fa-mouse-pointer mr-2"></i> ${out.title} | |
| </a> | |
| `; | |
| } else if (out.type === 'file') { | |
| // Specifically added to handle files like GRN CSV outputs | |
| document.getElementById('interactiveContainer').innerHTML += ` | |
| <a href="${out.url}" download class="flex-1 bg-indigo-700 hover:bg-indigo-600 text-white text-sm font-medium py-2 px-3 rounded shadow border border-indigo-600 text-center transition"> | |
| <i class="fas ${out.icon || 'fa-file-csv'} mr-2"></i> ${out.title} | |
| </a> | |
| `; | |
| } | |
| }); | |
| } else { | |
| alert("Pipeline Error: " + data.message); | |
| } | |
| } catch (err) { | |
| document.getElementById('loader').classList.add('hidden'); | |
| alert("Request completely failed. Ensure the Flask server is still running."); | |
| console.error(err); | |
| } | |
| }); | |
| </script> | |
| <style> | |
| .blink { animation: blinker 1.5s linear infinite; } | |
| @keyframes blinker { 50% { opacity: 0.5; } } | |
| </style> | |
| </body> | |
| </html> |