diff --git a/screenshots/about.png b/screenshots/about.png index 6b3dca3..ae634ce 100644 Binary files a/screenshots/about.png and b/screenshots/about.png differ diff --git a/screenshots/input_1.png b/screenshots/input_1.png index 1624d4c..42d9b79 100644 Binary files a/screenshots/input_1.png and b/screenshots/input_1.png differ diff --git a/screenshots/input_2.png b/screenshots/input_2.png index 61e2d7a..62f3087 100644 Binary files a/screenshots/input_2.png and b/screenshots/input_2.png differ diff --git a/screenshots/landing.png b/screenshots/landing.png index bb7a20b..501448c 100644 Binary files a/screenshots/landing.png and b/screenshots/landing.png differ diff --git a/screenshots/output.png b/screenshots/output.png index 1edc45f..4bb13e0 100644 Binary files a/screenshots/output.png and b/screenshots/output.png differ diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000..65d15e0 --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,526 @@ +/* ========================================= + Exoplanet Classifier - Cosmic Dark Theme + ========================================= */ + +:root { + /* Color Palette */ + --bg-dark: #0a0a0a; + --bg-card: rgba(255, 255, 255, 0.05); + --bg-card-hover: rgba(255, 255, 255, 0.08); + --accent-primary: #00BCFF; + --accent-secondary: #0077ff; + --text-main: #ffffff; + --text-muted: #a0a0a0; + --border-color: rgba(255, 255, 255, 0.1); + --glass-border: rgba(255, 255, 255, 0.15); + + /* Spacing & Layout */ + --container-width: 1200px; + --header-height: 80px; + --radius-lg: 24px; + --radius-md: 12px; + --radius-sm: 8px; + + /* Transitions */ + --transition-fast: 0.2s ease; + --transition-smooth: 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* Reset & Base Styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', sans-serif; +} + +body { + background-color: var(--bg-dark); + color: var(--text-main); + line-height: 1.6; + overflow-x: hidden; + min-height: 100vh; + background-image: + radial-gradient(circle at 10% 20%, rgba(0, 188, 255, 0.05) 0%, transparent 40%), + radial-gradient(circle at 90% 80%, rgba(0, 119, 255, 0.05) 0%, transparent 40%); +} + +a { + text-decoration: none; + color: inherit; + transition: var(--transition-fast); +} + +ul { + list-style: none; +} + +/* Typography */ +h1, h2, h3, h4, h5, h6 { + font-family: 'Lexend Deca', sans-serif; + font-weight: 700; + line-height: 1.2; +} + +.text-gradient { + background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* ========================================= + Layout Components + ========================================= */ + +/* Header */ +.site-header { + height: var(--header-height); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 5%; + background: rgba(10, 10, 10, 0.8); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + position: sticky; + top: 0; + z-index: 1000; + border-bottom: 1px solid var(--border-color); +} + +.logo-container { + display: flex; + align-items: center; + gap: 1rem; +} + +.nasa-logo { + height: 40px; + width: auto; +} + +.site-title { + font-size: 1.5rem; + letter-spacing: -0.5px; +} + +.site-title span { + font-size: 0.8rem; + color: var(--text-muted); + font-weight: 400; + display: block; + line-height: 1; + margin-top: 4px; +} + +.nav-link { + color: var(--accent-primary); + font-weight: 600; + position: relative; + padding: 0.5rem 0; +} + +.nav-link::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 0; + height: 2px; + background: var(--accent-primary); + transition: var(--transition-smooth); +} + +.nav-link:hover::after { + width: 100%; +} + +/* Main Container */ +.main-container { + max-width: var(--container-width); + margin: 0 auto; + padding: 2rem; +} + +/* ========================================= + Hero Section + ========================================= */ +.hero-section { + display: flex; + align-items: center; + justify-content: space-between; + min-height: calc(100vh - var(--header-height)); + gap: 4rem; + padding: 4rem 0; +} + +.hero-content { + flex: 1; +} + +.hero-subtitle { + color: var(--accent-primary); + font-weight: 600; + margin-bottom: 1rem; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 0.9rem; +} + +.hero-title { + font-size: 4rem; + margin-bottom: 1.5rem; +} + +.hero-description { + color: var(--text-muted); + font-size: 1.1rem; + margin-bottom: 2.5rem; + max-width: 600px; +} + +.hero-image { + flex: 1; + display: flex; + justify-content: center; + position: relative; +} + +.hero-img-wrapper { + width: 100%; + max-width: 500px; + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); + position: relative; +} + +.hero-img-wrapper::before { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(to bottom, transparent 50%, rgba(0, 188, 255, 0.2)); + pointer-events: none; +} + +.hero-img { + width: 100%; + height: auto; + display: block; + transform: scale(1.05); + transition: transform 10s ease; +} + +.hero-section:hover .hero-img { + transform: scale(1.1); +} + +/* Buttons */ +.btn { + display: inline-flex; + align-items: center; + gap: 0.8rem; + padding: 1rem 2rem; + border-radius: var(--radius-sm); + font-weight: 600; + cursor: pointer; + transition: var(--transition-smooth); + border: none; + font-size: 1rem; +} + +.btn-primary { + background: var(--text-main); + color: var(--bg-dark); + position: relative; + overflow: hidden; + z-index: 1; +} + +.btn-primary::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 0%; + height: 100%; + background: var(--accent-primary); + transition: var(--transition-smooth); + z-index: -1; +} + +.btn-primary:hover::before { + width: 100%; +} + +.btn-primary:hover { + color: var(--text-main); +} + +/* ========================================= + Form Section + ========================================= */ +.form-section { + padding: 6rem 0; + display: flex; + justify-content: center; +} + +.glass-card { + background: var(--bg-card); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border: 1px solid var(--glass-border); + border-radius: 40px; + padding: 4rem; + width: 100%; + max-width: 1000px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); +} + +.form-header { + text-align: center; + margin-bottom: 4rem; + position: relative; +} + +.form-title { + font-size: 3rem; +} + +.form-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; +} + +.input-group { + position: relative; + margin-bottom: 1rem; +} + +.input-field { + width: 100%; + background: transparent; + border: none; + border-bottom: 2px solid var(--border-color); + padding: 1rem 0; + color: var(--text-main); + font-size: 1rem; + transition: var(--transition-fast); +} + +.input-field:focus { + outline: none; + border-bottom-color: var(--accent-primary); +} + +.input-label { + position: absolute; + top: 1rem; + left: 0; + color: var(--text-muted); + pointer-events: none; + transition: var(--transition-fast); + font-size: 0.95rem; +} + +.input-field:focus ~ .input-label, +.input-field:not(:placeholder-shown) ~ .input-label { + top: -0.8rem; + font-size: 0.8rem; + color: var(--accent-primary); +} + +.form-actions { + grid-column: 1 / -1; + display: flex; + justify-content: center; + margin-top: 2rem; +} + +/* ========================================= + Modal + ========================================= */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.8); + backdrop-filter: blur(5px); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; + opacity: 0; + visibility: hidden; + transition: var(--transition-smooth); +} + +.modal-overlay.active { + opacity: 1; + visibility: visible; +} + +.modal-content { + background: #1a1a1a; + border: 1px solid var(--glass-border); + border-radius: var(--radius-lg); + padding: 2.5rem; + width: 90%; + max-width: 450px; + transform: translateY(20px); + transition: var(--transition-smooth); + position: relative; +} + +.modal-overlay.active .modal-content { + transform: translateY(0); +} + +.close-modal { + position: absolute; + top: 1.5rem; + right: 1.5rem; + background: none; + border: none; + color: var(--text-muted); + font-size: 1.5rem; + cursor: pointer; + transition: var(--transition-fast); +} + +.close-modal:hover { + color: var(--text-main); +} + +.result-header { + margin-bottom: 1.5rem; + text-align: center; +} + +.prediction-result { + font-size: 1.5rem; + color: var(--accent-primary); + margin-top: 0.5rem; +} + +.prob-item { + margin-bottom: 1rem; +} + +.prob-label { + display: flex; + justify-content: space-between; + font-size: 0.9rem; + margin-bottom: 0.4rem; + color: var(--text-muted); +} + +.prob-bar-bg { + height: 8px; + background: rgba(255, 255, 255, 0.1); + border-radius: 4px; + overflow: hidden; +} + +.prob-bar-fill { + height: 100%; + background: var(--accent-primary); + width: 0; + transition: width 1s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* ========================================= + About Page Styles + ========================================= */ +.about-content { + background: var(--bg-card); + border: 1px solid var(--glass-border); + border-radius: var(--radius-lg); + padding: 3rem; + margin-top: 2rem; +} + +.about-section { + margin-bottom: 3rem; +} + +.about-section h2 { + color: var(--accent-primary); + margin-bottom: 1rem; + font-size: 1.8rem; +} + +.data-table { + width: 100%; + border-collapse: collapse; + margin-top: 1.5rem; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-sm); + overflow: hidden; +} + +.data-table th, +.data-table td { + padding: 1rem; + text-align: left; + border-bottom: 1px solid var(--border-color); +} + +.data-table th { + background: rgba(0, 188, 255, 0.1); + color: var(--accent-primary); + font-weight: 600; +} + +.data-table tr:last-child td { + border-bottom: none; +} + +.data-table tr:hover td { + background: rgba(255, 255, 255, 0.02); +} + +/* ========================================= + Responsive Design + ========================================= */ +@media (max-width: 968px) { + .hero-section { + flex-direction: column-reverse; + text-align: center; + padding-top: 2rem; + } + + .hero-content { + display: flex; + flex-direction: column; + align-items: center; + } + + .hero-title { + font-size: 3rem; + } + + .form-grid { + grid-template-columns: 1fr; + } + + .glass-card { + padding: 2rem; + } +} + +@media (max-width: 480px) { + .site-title { + font-size: 1.2rem; + } + + .hero-title { + font-size: 2.5rem; + } + + .form-title { + font-size: 2rem; + } +} diff --git a/static/js/main.js b/static/js/main.js new file mode 100644 index 0000000..de0f46e --- /dev/null +++ b/static/js/main.js @@ -0,0 +1,147 @@ +document.addEventListener('DOMContentLoaded', () => { + // Smooth Scroll + const scrollBtn = document.getElementById('scroll-to-form'); + if (scrollBtn) { + scrollBtn.addEventListener('click', (e) => { + e.preventDefault(); + document.getElementById('form-section').scrollIntoView({ + behavior: 'smooth' + }); + }); + } + + // Input Animation & Label Handling + const inputs = document.querySelectorAll('.input-field'); + inputs.forEach(input => { + // Trigger label animation on load if value exists + if (input.value) { + input.classList.add('has-value'); + } + + input.addEventListener('input', () => { + if (input.value.trim() !== '') { + input.classList.add('has-value'); + } else { + input.classList.remove('has-value'); + } + }); + }); + + // Form Submission + const form = document.getElementById('predictForm'); + const modal = document.getElementById('resultModal'); + const closeModalBtn = document.getElementById('closeModal'); + const resultsContainer = document.getElementById('resultsContainer'); + + if (form) { + form.addEventListener('submit', async (e) => { + e.preventDefault(); + + const submitBtn = form.querySelector('button[type="submit"]'); + const originalBtnText = submitBtn.innerHTML; + + // Loading State + submitBtn.innerHTML = ' Analyzing...'; + submitBtn.disabled = true; + + // Collect Data + const formData = {}; + inputs.forEach(input => { + formData[input.id] = parseFloat(input.value); + }); + + try { + const response = await fetch('/predict', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData) + }); + + const data = await response.json(); + + if (data.error) { + throw new Error(data.error); + } + + // Populate Results + displayResults(data); + openModal(); + + } catch (error) { + console.error('Error:', error); + alert('An error occurred during prediction. Please check your inputs.'); + } finally { + // Reset Button + submitBtn.innerHTML = originalBtnText; + submitBtn.disabled = false; + } + }); + } + + // Modal Functions + function openModal() { + modal.classList.add('active'); + document.body.style.overflow = 'hidden'; + } + + function closeModal() { + modal.classList.remove('active'); + document.body.style.overflow = ''; + } + + if (closeModalBtn) { + closeModalBtn.addEventListener('click', closeModal); + } + + // Close on click outside + if (modal) { + modal.addEventListener('click', (e) => { + if (e.target === modal) { + closeModal(); + } + }); + } + + // Helper: Display Results + function displayResults(data) { + const predictionEl = document.getElementById('predictionResult'); + const barsContainer = document.getElementById('probabilityBars'); + + // Set Prediction Text + predictionEl.textContent = data.prediction; + + // Clear previous bars + barsContainer.innerHTML = ''; + + // Sort probabilities + const sortedProbs = Object.entries(data.probabilities) + .sort(([,a], [,b]) => b - a); + + // Create Bars + sortedProbs.forEach(([label, prob]) => { + const percentage = (prob * 100).toFixed(1); + + const item = document.createElement('div'); + item.className = 'prob-item'; + + item.innerHTML = ` +
- The Exoplanet Classifier is a project developed by Team Ontohin 4b for the - NASA Space Apps Challenge 2025. -
- -- The objective of this web app is to predict new exoplanet’s status - (CONFIRMED, CANDIDATE, FALSE POSITIVE) by evaluating user-given inputs. -
- -- The user-given data is sent to the model via a Flask API endpoint. - Then, the model predicts the classes and also returns a probability for each class - (which you can see after hitting the “Predict” button). -
- -- We have used the widely known Scikit-learn library to build it from the ground up. - More info about the ML part can be found at the README file of the repository. -
- -- This is one of the most widely used models provided by Scikit-learn and also very suitable for our objective. - It predicts the result in three different classes: -
- -- The model also returns a probability (up to 3 decimal digits) of its prediction for each of those 3 classes. -
- -- The model is trained on 14 different features (including the output column) sourced from - NASA’s Kepler Object of Interest dataset. To run the prediction, the user needs to provide - 13 different values (all in real numbers) as input. Here is a list of them: -
- -| Input Feature | -Unit | -Description | -
|---|---|---|
| Orbital Period | -Days | -Time the planet takes to complete one orbit around its star. | -
| Transit Epoch | -BJD - 2,454,833.0 | -Reference time when the planet crosses in front of its star. | -
| Transit Depth | -ppm (parts per million) | -How much the star’s brightness dips during transit. | -
| Planet Radius | -Earth radius | -Size of the planet compared to Earth. | -
| Semi-Major Axis | -AU (approx) | -Average distance between the planet and its star. | -
| Inclination | -Degrees | -Tilt of the planet’s orbit relative to our view. | -
| Equilibrium Temperature | -Kelvin | -Estimated average surface temperature of the planet. | -
| Insolation Flux | -Earth flux | -Amount of starlight the planet receives compared to Earth. | -
| Impact Parameter | -None | -How centrally the planet crosses the star (0 = center, 1 = edge). | -
| Planet/Star Radius Ratio | -None | -Ratio of planet’s size to its star’s size. | -
| Stellar Density | -gm/cm³ | -Average density of the host star. | -
| Planet–Star Distance | -R★ (stellar radii) | -Distance from the planet to the star, in units of stellar radii. | -
| Number of Transits | -None | -How many times the planet has been observed passing in front of its star. | -
- For more information about the entire project, check the README file of the project repository. -
- -- Thank you for trying out our work! We hope you enjoyed the concept and our idea to solve this astronomical - challenge with the power of machine learning. -
- -Have a great day!
- -
-
- Click here to visit the GitHub repository.
+{% extends "base.html" %}
+
+{% block title %}About - Exoplanet Classifier{% endblock %}
+
+{% block content %}
+
+ The Exoplanet Classifier is an advanced machine learning tool developed by
+ Team Ontohin 4b for the NASA Space Apps Challenge 2025.
+ It leverages state-of-the-art ensemble algorithms to assist astronomers in identifying potential exoplanets.
+
+ The primary goal is to automate the classification of transit signals. By analyzing light curves and orbital parameters,
+ the model categorizes candidates into three distinct classes:
+
+ Built on Scikit-learn, the system employs a Stacking Ensemble Classifier.
+ This combines the strengths of Random Forest and XGBoost,
+ orchestrated by a Logistic Regression meta-classifier.
+ The model requires 13 specific orbital and transit features derived from NASA's Kepler mission data:
+ While this model achieves high accuracy on the validation set, no ML model is infallible.
+ Predictions should be used as a preliminary screening tool rather than absolute confirmation.
+ The model is optimized for Kepler-like data distributions.
+
+ © 2025 Ontohin 4b. Licensed under MIT.
+
- This project is developed by the members of Ontohin 4b.
+ Harness the power of Machine Learning to classify exoplanets.
+ Input transit data and let our advanced ensemble model determine if it's a
+ Confirmed Planet, Candidate, or False Positive.
+
- Developed by team Ontohin 4b. Here, you will need to provide
- some numerical data (such as orbital period, transit depth etc.) and a specially trained ML model
- will classify it under 3 classes:
- Confirmed planet, Planetary Candidate or False Positive.
- Enter the transit details below to generate a prediction.
- Enter the detailsAbout the Project
+ Objective
+
+
+ Technical Architecture
+
+ The backend is powered by Flask, serving a robust API that processes user inputs
+ and returns real-time predictions with probability confidence scores.
+ Input Parameters
+
+
+
+
+
+
+
+ Feature
+ Unit
+ Description
+
+
+ Orbital Period
+ Days
+ Time taken to complete one full orbit.
+
+
+ Transit Epoch
+ BJD
+ Time of the center of the first transit.
+
+
+ Transit Depth
+ ppm
+ Fraction of stellar flux lost during transit.
+
+
+ Planet Radius
+ Earth Radii
+ Estimated radius of the planet.
+
+
+ Semi-Major Axis
+ AU
+ Average distance from the host star.
+
+
+ Inclination
+ Degrees
+ Angle of the orbital plane.
+
+
+ Equilibrium Temp
+ Kelvin
+ Theoretical surface temperature.
+
+
+ Insolation Flux
+ Earth Flux
+ Incident solar radiation.
+
+
+ Impact Parameter
+ -
+ Sky-projected distance at conjunction.
+
+
+ Radius Ratio
+ -
+ Ratio of planet radius to star radius.
+
+
+ Stellar Density
+ g/cm³
+ Density of the host star.
+
+
+ Planet-Star Dist
+ Stellar Radii
+ Distance scaled by star size.
+
+
+
+ Num Transits
+ Count
+ Total number of transit events observed.
+ Disclaimer
+
-
-
- Check the LICENSE file of the repository for copyright
- information.
-
+
+ Exoplanet Classifier
+ NASA Space Apps Challenge
+
+
-
- Int. Space Apps Challenge
-
- Presented by Ontohin 4b
-
-
- Welcome to the Future
+
+ Discover New
+
+ Worlds
+
- Welcome, To The
- Exoplanet-Classifier
- Input Parameters
+
- The
-
-
Exoplanet
Classifier
-