ayyuce's picture
Update templates/index.html
78b0376 verified
Raw
History Blame Contribute Delete
20.2 kB
<!DOCTYPE html>
<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>