Mentors4EDU's picture
Upload 33 files
7a92197 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cancer@Home v2 - Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #333;
min-height: 100vh;
}
.header {
background: rgba(0, 0, 0, 0.2);
color: white;
padding: 20px;
text-align: center;
backdrop-filter: blur(10px);
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
opacity: 0.9;
}
.container {
max-width: 1400px;
margin: 20px auto;
padding: 0 20px;
}
.tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.tab-button {
background: rgba(255, 255, 255, 0.9);
border: none;
padding: 15px 30px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
font-weight: 500;
transition: all 0.3s;
}
.tab-button:hover {
background: white;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.tab-button.active {
background: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.card {
background: white;
border-radius: 12px;
padding: 25px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.card h3 {
color: #667eea;
margin-bottom: 15px;
font-size: 1.3em;
}
.stat {
font-size: 2.5em;
font-weight: bold;
color: #764ba2;
margin: 10px 0;
}
.graph-container {
background: white;
border-radius: 12px;
padding: 25px;
margin-bottom: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
#neo4j-viz {
width: 100%;
height: 600px;
border: 2px solid #e0e0e0;
border-radius: 8px;
}
.button {
background: #667eea;
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}
.button:hover {
background: #5568d3;
}
.task-list {
list-style: none;
}
.task-item {
background: #f5f5f5;
padding: 15px;
margin: 10px 0;
border-radius: 6px;
border-left: 4px solid #667eea;
}
.task-item.completed {
border-left-color: #4caf50;
}
.task-item.running {
border-left-color: #ff9800;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
.status-pending { background: #ffc107; color: #000; }
.status-running { background: #2196f3; color: white; }
.status-completed { background: #4caf50; color: white; }
.status-failed { background: #f44336; color: white; }
.input-group {
margin: 15px 0;
}
.input-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
.input-group input, .input-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
}
.project-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 8px;
margin: 10px 0;
cursor: pointer;
transition: transform 0.2s;
}
.project-card:hover {
transform: translateY(-3px);
}
.loading {
text-align: center;
padding: 40px;
color: #667eea;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="header">
<h1>🧬 Cancer@Home v2</h1>
<p>Distributed Cancer Genomics Research Platform</p>
</div>
<div class="container">
<div class="tabs">
<button class="tab-button active" onclick="showTab('dashboard')">📊 Dashboard</button>
<button class="tab-button" onclick="showTab('neo4j')">🔍 Neo4j Visualization</button>
<button class="tab-button" onclick="showTab('boinc')">⚡ BOINC Tasks</button>
<button class="tab-button" onclick="showTab('gdc')">📚 GDC Data</button>
<button class="tab-button" onclick="showTab('pipeline')">🧪 Analysis Pipeline</button>
</div>
<!-- Dashboard Tab -->
<div id="dashboard" class="tab-content active">
<div class="cards" id="stats-cards">
<div class="card">
<h3>Total Genes</h3>
<div class="stat" id="total-genes">-</div>
</div>
<div class="card">
<h3>Total Mutations</h3>
<div class="stat" id="total-mutations">-</div>
</div>
<div class="card">
<h3>Total Patients</h3>
<div class="stat" id="total-patients">-</div>
</div>
<div class="card">
<h3>Cancer Types</h3>
<div class="stat" id="total-cancer-types">-</div>
</div>
</div>
<div class="graph-container">
<h3>Mutation Distribution by Cancer Type</h3>
<canvas id="mutation-chart"></canvas>
</div>
</div>
<!-- Neo4j Visualization Tab -->
<div id="neo4j" class="tab-content">
<div class="graph-container">
<h3>Cancer Genomics Knowledge Graph</h3>
<div id="neo4j-viz"></div>
</div>
</div>
<!-- BOINC Tasks Tab -->
<div id="boinc" class="tab-content">
<div class="cards">
<div class="card">
<h3>Submit New Task</h3>
<div class="input-group">
<label>Task Type</label>
<select id="task-type">
<option value="variant_calling">Variant Calling</option>
<option value="blast_search">BLAST Search</option>
<option value="alignment">Sequence Alignment</option>
</select>
</div>
<div class="input-group">
<label>Input File</label>
<input type="text" id="input-file" placeholder="path/to/input.fastq">
</div>
<button class="button" onclick="submitBoincTask()">Submit Task</button>
</div>
<div class="card">
<h3>BOINC Statistics</h3>
<div id="boinc-stats"></div>
</div>
</div>
<div class="card">
<h3>Active Tasks</h3>
<ul class="task-list" id="task-list"></ul>
</div>
</div>
<!-- GDC Data Tab -->
<div id="gdc" class="tab-content">
<div class="card">
<h3>Available GDC Projects</h3>
<div id="gdc-projects"></div>
</div>
</div>
<!-- Pipeline Tab -->
<div id="pipeline" class="tab-content">
<div class="cards">
<div class="card">
<h3>FASTQ Quality Control</h3>
<p>Run quality control analysis on sequencing data</p>
<button class="button" style="margin-top: 15px;">Run QC</button>
</div>
<div class="card">
<h3>BLAST Search</h3>
<p>Perform sequence alignment and homology search</p>
<button class="button" style="margin-top: 15px;">Run BLAST</button>
</div>
<div class="card">
<h3>Variant Calling</h3>
<p>Identify genetic variants from sequencing data</p>
<button class="button" style="margin-top: 15px;">Call Variants</button>
</div>
</div>
</div>
</div>
<script>
// Tab switching
function showTab(tabName) {
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
document.querySelectorAll('.tab-button').forEach(btn => {
btn.classList.remove('active');
});
document.getElementById(tabName).classList.add('active');
event.target.classList.add('active');
if (tabName === 'dashboard') loadDashboard();
else if (tabName === 'neo4j') loadNeo4jViz();
else if (tabName === 'boinc') loadBoincTasks();
else if (tabName === 'gdc') loadGdcProjects();
}
// Load dashboard data
async function loadDashboard() {
try {
const response = await fetch('/api/neo4j/summary');
const data = await response.json();
document.getElementById('total-genes').textContent = data.genes || 0;
document.getElementById('total-mutations').textContent = data.mutations || 0;
document.getElementById('total-patients').textContent = data.patients || 0;
document.getElementById('total-cancer-types').textContent = data.cancer_types || 0;
createMutationChart();
} catch (error) {
console.error('Error loading dashboard:', error);
}
}
// Create mutation chart
function createMutationChart() {
const ctx = document.getElementById('mutation-chart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Breast Cancer', 'Lung Adenocarcinoma', 'Colon Adenocarcinoma', 'Glioblastoma'],
datasets: [{
label: 'Mutations',
data: [245, 189, 156, 203],
backgroundColor: [
'rgba(102, 126, 234, 0.8)',
'rgba(118, 75, 162, 0.8)',
'rgba(237, 100, 166, 0.8)',
'rgba(255, 154, 158, 0.8)'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: { display: false }
}
}
});
}
// Load Neo4j visualization
function loadNeo4jViz() {
const viz = document.getElementById('neo4j-viz');
viz.innerHTML = '<div class="loading"><div class="spinner"></div><p>Loading graph visualization...</p></div>';
// Simulate graph visualization with D3.js
setTimeout(() => {
const width = viz.clientWidth;
const height = 600;
viz.innerHTML = '';
const svg = d3.select('#neo4j-viz')
.append('svg')
.attr('width', width)
.attr('height', height);
// Sample data
const nodes = [
{ id: 'TP53', type: 'gene', x: width/2, y: height/2 },
{ id: 'BRCA1', type: 'gene', x: width/3, y: height/3 },
{ id: 'KRAS', type: 'gene', x: 2*width/3, y: height/3 },
{ id: 'Patient 1', type: 'patient', x: width/4, y: 3*height/4 },
{ id: 'Patient 2', type: 'patient', x: 3*width/4, y: 3*height/4 },
{ id: 'Breast Cancer', type: 'cancer', x: width/2, y: height/4 }
];
const links = [
{ source: 'Patient 1', target: 'TP53' },
{ source: 'Patient 1', target: 'Breast Cancer' },
{ source: 'Patient 2', target: 'KRAS' },
{ source: 'TP53', target: 'Breast Cancer' }
];
// Draw links
svg.selectAll('line')
.data(links)
.enter()
.append('line')
.attr('x1', d => nodes.find(n => n.id === d.source).x)
.attr('y1', d => nodes.find(n => n.id === d.source).y)
.attr('x2', d => nodes.find(n => n.id === d.target).x)
.attr('y2', d => nodes.find(n => n.id === d.target).y)
.attr('stroke', '#999')
.attr('stroke-width', 2);
// Draw nodes
svg.selectAll('circle')
.data(nodes)
.enter()
.append('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', 20)
.attr('fill', d => {
if (d.type === 'gene') return '#667eea';
if (d.type === 'patient') return '#764ba2';
return '#ed64a6';
});
// Draw labels
svg.selectAll('text')
.data(nodes)
.enter()
.append('text')
.attr('x', d => d.x)
.attr('y', d => d.y - 25)
.attr('text-anchor', 'middle')
.text(d => d.id)
.attr('font-size', '12px')
.attr('fill', '#333');
}, 500);
}
// Load BOINC tasks
async function loadBoincTasks() {
try {
const [tasksResponse, statsResponse] = await Promise.all([
fetch('/api/boinc/tasks'),
fetch('/api/boinc/statistics')
]);
const tasksData = await tasksResponse.json();
const statsData = await statsResponse.json();
// Display tasks
const taskList = document.getElementById('task-list');
taskList.innerHTML = tasksData.tasks.map(task => `
<li class="task-item ${task.status}">
<strong>${task.name}</strong>
<span class="status-badge status-${task.status}">${task.status}</span>
<div style="margin-top: 8px; font-size: 14px; color: #666;">
Type: ${task.workunit_type} | Created: ${new Date(task.created_at).toLocaleString()}
</div>
</li>
`).join('');
// Display statistics
const statsDiv = document.getElementById('boinc-stats');
statsDiv.innerHTML = `
<p><strong>Total Tasks:</strong> ${statsData.total_tasks}</p>
<p><strong>Completed:</strong> ${statsData.by_status?.completed || 0}</p>
<p><strong>Running:</strong> ${statsData.by_status?.running || 0}</p>
<p><strong>Pending:</strong> ${statsData.by_status?.pending || 0}</p>
`;
} catch (error) {
console.error('Error loading BOINC tasks:', error);
}
}
// Submit BOINC task
async function submitBoincTask() {
const taskType = document.getElementById('task-type').value;
const inputFile = document.getElementById('input-file').value;
if (!inputFile) {
alert('Please provide an input file path');
return;
}
try {
const response = await fetch('/api/boinc/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ workunit_type: taskType, input_file: inputFile })
});
const data = await response.json();
alert(`Task submitted successfully! Task ID: ${data.task_id}`);
loadBoincTasks();
} catch (error) {
console.error('Error submitting task:', error);
alert('Failed to submit task');
}
}
// Load GDC projects
async function loadGdcProjects() {
try {
const response = await fetch('/api/gdc/projects');
const data = await response.json();
const projectsDiv = document.getElementById('gdc-projects');
projectsDiv.innerHTML = data.projects.map(project => `
<div class="project-card">
<h4>${project.name}</h4>
<p>Project ID: ${project.id}</p>
<p>Cases: ${project.cases}</p>
</div>
`).join('');
} catch (error) {
console.error('Error loading GDC projects:', error);
}
}
// Initialize dashboard on load
window.onload = () => {
loadDashboard();
};
</script>
</body>
</html>