Antigravity
Stable deployment version: Lazy loading and Docker optimized
2d802f0
{% extends "layout.html" %}
{% block title %}DBSCAN Clusters - Quantum AI{% endblock %}
{% block page_header %}
<h1>DBSCAN Clusters</h1>
<p>Density-Based Spatial Clustering of Applications with Noise (DBSCAN).</p>
{% endblock %}
{% block content %}
<div class="service-panel glass-card">
<form action="/dbscan" method="post" enctype="multipart/form-data" class="quantum-form">
<div class="upload-zone" id="dropZone">
<i class="fas fa-braille upload-icon"></i>
<div class="upload-text">
<strong>Upload Data Structure</strong>
<span>Supports .CSV or .XLSX datasets</span>
</div>
<input type="file" name="file" accept=".csv, .xlsx" required>
</div>
<div class="settings-grid">
<div class="input-group">
<label>Epsilon (eps)</label>
<input type="number" name="eps" value="0.5" min="0.01" max="10" step="0.01" required>
</div>
<div class="input-group">
<label>Min Samples</label>
<input type="number" name="min_samples" value="5" min="1" max="100" required>
</div>
</div>
<button type="submit" class="btn-quantum full-width">
<i class="fas fa-project-diagram"></i> Analyze Density
</button>
</form>
{% if error %}
<div class="error-msg animate-fade-in">
<i class="fas fa-exclamation-triangle"></i> {{ error }}
</div>
{% endif %}
{% if plot_url %}
<div class="result-container animate-fade-in">
<div class="result-header">Density Map Visualization</div>
<div class="visualization-box">
<img src="data:image/png;base64,{{ plot_url }}" alt="DBSCAN Plot">
</div>
{% if cluster_info %}
<div class="cluster-stats">
<label>Density Distribution (-1 denotes noise)</label>
<div class="stats-grid">
{% for cluster, count in cluster_info.items() %}
<div class="stat-card {% if cluster|int == -1 %}noise-card{% endif %}">
<span class="cluster-id">{% if cluster|int == -1 %}Noise (Outliers){% else %}Cluster {{ cluster }}{%
endif %}</span>
<span class="count-value">{{ count }} Entities</span>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% endif %}
</div>
<style>
.service-panel {
max-width: 900px;
margin: 0 auto;
}
.settings-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin-top: 1.5rem;
}
.input-group label {
font-size: 0.85rem;
font-weight: 700;
color: var(--text-secondary);
text-transform: uppercase;
margin-bottom: 0.5rem;
display: block;
}
input[type="number"] {
background: rgba(0, 0, 0, 0.2);
border: 1px solid var(--glass-border);
border-radius: var(--radius-md);
padding: 0.75rem 1rem;
color: var(--text-primary);
font-size: 1.1rem;
width: 100%;
}
.visualization-box {
background: white;
padding: 1.5rem;
border-radius: var(--radius-lg);
margin-top: 1rem;
display: flex;
justify-content: center;
overflow: hidden;
}
.visualization-box img {
max-width: 100%;
height: auto;
}
.cluster-stats {
margin-top: 2rem;
}
.cluster-stats label {
color: var(--text-secondary);
font-weight: 600;
display: block;
margin-bottom: 1rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 1rem;
}
.stat-card {
background: rgba(255, 255, 255, 0.03);
padding: 1.25rem;
border-radius: var(--radius-md);
display: flex;
flex-direction: column;
border-left: 3px solid var(--accent-blue);
}
.stat-card.noise-card {
border-left-color: #ef4444;
}
.cluster-id {
font-size: 0.8rem;
font-weight: 700;
color: var(--text-secondary);
text-transform: uppercase;
margin-bottom: 4px;
}
.count-value {
font-size: 1.2rem;
font-weight: 800;
}
.error-msg {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
padding: 1rem;
border-radius: var(--radius-md);
margin: 1rem 0;
}
</style>
{% endblock %}