statisticalplumber's picture
Create app1/index.html
b5137ae verified
Raw
History Blame Contribute Delete
19.8 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lotka-Volterra Predator-Prey Simulation</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
color: #333;
}
h1 {
text-align: center;
color: #2c3e50;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h2 {
color: #3498db;
margin-top: 30px;
}
.container {
background-color: white;
padding: 25px;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
margin-bottom: 20px;
}
.description {
background-color: #e3f2fd;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
border-left: 4px solid #3498db;
}
canvas {
border: 1px solid #ddd;
margin-top: 20px;
background-color: #f9f9f9;
border-radius: 8px;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 25px;
}
.control-group {
flex: 1;
min-width: 200px;
background-color: #f8f9fa;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.control-group h3 {
margin-top: 0;
color: #2c3e50;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #2c3e50;
}
input[type="range"] {
width: 100%;
margin-bottom: 5px;
}
.value-display {
text-align: right;
font-size: 14px;
color: #7f8c8d;
font-weight: bold;
}
.initial-controls {
display: flex;
gap: 15px;
margin-top: 10px;
}
.initial-controls input {
flex: 1;
padding: 8px;
border-radius: 4px;
border: 1px solid #ddd;
}
button {
background-color: #3498db;
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
margin-top: 15px;
width: 100%;
font-size: 16px;
transition: all 0.3s ease;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
button:hover {
background-color: #2980b9;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.legend {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 15px;
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
}
.legend-color {
width: 15px;
height: 15px;
border-radius: 3px;
}
.help-section {
background-color: #fff8e1;
padding: 20px;
border-radius: 8px;
margin-top: 25px;
border-left: 4px solid #f39c12;
}
.help-section h3 {
margin-top: 0;
color: #e67e22;
}
.variable {
display: flex;
margin-bottom: 10px;
padding: 8px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.variable-name {
font-weight: bold;
color: #2c3e50;
min-width: 140px;
}
.variable-desc {
flex: 1;
}
.equation {
background-color: #f8f9fa;
padding: 10px;
border-radius: 6px;
margin: 15px 0;
font-family: monospace;
text-align: center;
border-left: 3px solid #3498db;
}
</style>
</head>
<body>
<div class="container">
<h1>Lotka-Volterra Predator-Prey Simulation</h1>
<div class="description">
<p>This simulation demonstrates the classic Lotka-Volterra model of predator-prey dynamics. The populations of prey and predators oscillate in a cyclical pattern based on the mathematical relationships between their growth rates, predation, and death rates.</p>
</div>
<canvas id="simulationCanvas" width="800" height="400"></canvas>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background-color: #3498db;"></div>
<span>Prey Population</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #e74c3c;"></div>
<span>Predator Population</span>
</div>
</div>
<div class="controls">
<div class="control-group">
<h3>Population Parameters</h3>
<label for="initialPrey">Initial Prey Population: <span id="initialPreyValue">40</span></label>
<input type="range" id="initialPrey" min="1" max="200" step="1" value="40">
<label for="initialPredator">Initial Predator Population: <span id="initialPredatorValue">9</span></label>
<input type="range" id="initialPredator" min="1" max="50" step="1" value="9">
<div class="initial-controls">
<input type="number" id="preyInput" min="1" max="200" value="40">
<input type="number" id="predatorInput" min="1" max="50" value="9">
</div>
</div>
<div class="control-group">
<h3>Environmental Parameters</h3>
<label for="preyRate">Prey Reproduction Rate: <span id="preyRateValue">0.1</span></label>
<input type="range" id="preyRate" min="0.01" max="0.5" step="0.01" value="0.1">
<label for="predationRate">Predation Rate: <span id="predationRateValue">0.01</span></label>
<input type="range" id="predationRate" min="0.001" max="0.1" step="0.001" value="0.01">
<label for="predatorDeathRate">Predator Death Rate: <span id="predatorDeathRateValue">0.1</span></label>
<input type="range" id="predatorDeathRate" min="0.01" max="0.5" step="0.01" value="0.1">
<label for="predatorEfficiency">Predator Efficiency: <span id="predatorEfficiencyValue">0.01</span></label>
<input type="range" id="predatorEfficiency" min="0.001" max="0.1" step="0.001" value="0.01">
</div>
</div>
<button id="resetBtn">Reset Simulation</button>
</div>
<div class="help-section">
<h3>Lotka-Volterra Model Variables</h3>
<div class="variable">
<div class="variable-name">X (Prey)</div>
<div class="variable-desc">Population of prey species. Increases when not being eaten and decreases due to predation.</div>
</div>
<div class="variable">
<div class="variable-name">Y (Predator)</div>
<div class="variable-desc">Population of predator species. Increases when consuming prey and decreases due to natural death.</div>
</div>
<div class="variable">
<div class="variable-name">α</div>
<div class="variable-desc">Prey reproduction rate. Determines how quickly prey population grows in the absence of predators.</div>
</div>
<div class="variable">
<div class="variable-name">β</div>
<div class="variable-desc">Predation rate. Determines how effectively predators consume prey.</div>
</div>
<div class="variable">
<div class="variable-name">γ</div>
<div class="variable-desc">Predator death rate. Determines how quickly predators die in the absence of prey.</div>
</div>
<div class="variable">
<div class="variable-name">δ</div>
<div class="variable-desc">Predator efficiency. Determines how effectively predators convert consumed prey into predator offspring.</div>
</div>
<h3>Mathematical Equations</h3>
<div class="equation">dX/dt = αX - βXY</div>
<div class="equation">dY/dt = δXY - γY</div>
<h3>How to Use This Simulation</h3>
<p>This simulation shows the oscillating relationship between prey and predator populations. Adjust parameters to see how they affect population dynamics:</p>
<ul>
<li>Higher prey reproduction rate (α) leads to faster prey population growth</li>
<li>Higher predation rate (β) causes more rapid decline in prey population</li>
<li>Higher predator death rate (γ) causes faster predator decline when prey is scarce</li>
<li>Higher predator efficiency (δ) allows predators to grow faster when prey is abundant</li>
</ul>
</div>
<script>
// Canvas setup
const canvas = document.getElementById('simulationCanvas');
const ctx = canvas.getContext('2d');
// Simulation parameters
let params = {
preyRate: 0.1,
predationRate: 0.01,
predatorDeathRate: 0.1,
predatorEfficiency: 0.01
};
// Initial populations with user controls
let preyPopulation = 40;
let predatorPopulation = 9;
// Simulation variables
const dt = 0.01; // Time step
let time = 0;
const maxTime = 50;
// History arrays for plotting
let preyHistory = [];
let predatorHistory = [];
let timeHistory = [];
// Update value displays
function updateValueDisplays() {
document.getElementById('preyRateValue').textContent = params.preyRate.toFixed(2);
document.getElementById('predationRateValue').textContent = params.predationRate.toFixed(3);
document.getElementById('predatorDeathRateValue').textContent = params.predatorDeathRate.toFixed(2);
document.getElementById('predatorEfficiencyValue').textContent = params.predatorEfficiency.toFixed(3);
document.getElementById('initialPreyValue').textContent = preyPopulation;
document.getElementById('initialPredatorValue').textContent = predatorPopulation;
}
// Update parameters from sliders
function updateParams() {
params.preyRate = parseFloat(document.getElementById('preyRate').value);
params.predationRate = parseFloat(document.getElementById('predationRate').value);
params.predatorDeathRate = parseFloat(document.getElementById('predatorDeathRate').value);
params.predatorEfficiency = parseFloat(document.getElementById('predatorEfficiency').value);
updateValueDisplays();
}
// Update initial populations from inputs
function updateInitialPopulations() {
const preyInput = document.getElementById('preyInput');
const predatorInput = document.getElementById('predatorInput');
if (preyInput.value >= 1 && preyInput.value <= 200) {
preyPopulation = parseInt(preyInput.value);
}
if (predatorInput.value >= 1 && predatorInput.value <= 50) {
predatorPopulation = parseInt(predatorInput.value);
}
updateValueDisplays();
}
// Lotka-Volterra equations
function calculatePopulations() {
const prey = preyPopulation;
const predator = predatorPopulation;
// Calculate rates of change
const dPrey = params.preyRate * prey - params.predationRate * prey * predator;
const dPredator = params.predatorEfficiency * params.predationRate * prey * predator - params.predatorDeathRate * predator;
// Update populations
preyPopulation += dPrey * dt;
predatorPopulation += dPredator * dt;
// Ensure populations don't go negative
preyPopulation = Math.max(0, preyPopulation);
predatorPopulation = Math.max(0, predatorPopulation);
// Store history for plotting
timeHistory.push(time);
preyHistory.push(preyPopulation);
predatorHistory.push(predatorPopulation);
time += dt;
}
// Draw the simulation
function drawSimulation() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw axes
ctx.beginPath();
ctx.strokeStyle = '#95a5a6';
ctx.lineWidth = 1;
// X-axis
ctx.moveTo(50, canvas.height - 50);
ctx.lineTo(canvas.width - 50, canvas.height - 50);
// Y-axis
ctx.moveTo(50, 50);
ctx.lineTo(50, canvas.height - 50);
ctx.stroke();
// Draw labels
ctx.fillStyle = '#2c3e50';
ctx.font = '14px Arial';
ctx.fillText('Time', canvas.width/2, canvas.height - 20);
ctx.save();
ctx.translate(15, canvas.height/2);
ctx.rotate(-Math.PI/2);
ctx.fillText('Population', 0, 0);
ctx.restore();
// Draw grid
ctx.strokeStyle = '#ecf0f1';
ctx.lineWidth = 0.5;
// Vertical grid lines
for (let i = 1; i < 10; i++) {
const x = 50 + (i * (canvas.width - 100) / 10);
ctx.beginPath();
ctx.moveTo(x, 50);
ctx.lineTo(x, canvas.height - 50);
ctx.stroke();
}
// Horizontal grid lines
for (let i = 1; i < 5; i++) {
const y = 50 + (i * (canvas.height - 100) / 5);
ctx.beginPath();
ctx.moveTo(50, y);
ctx.lineTo(canvas.width - 50, y);
ctx.stroke();
}
// Scale populations for drawing
const maxPrey = Math.max(...preyHistory, preyPopulation) * 1.2;
const maxPredator = Math.max(...predatorHistory, predatorPopulation) * 1.2;
// Draw population curves
ctx.beginPath();
ctx.strokeStyle = '#3498db';
ctx.lineWidth = 2;
// Draw prey curve
for (let i = 0; i < preyHistory.length; i++) {
const x = 50 + (timeHistory[i] / maxTime) * (canvas.width - 100);
const y = canvas.height - 50 - (preyHistory[i] / maxPrey) * (canvas.height - 100);
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
// Draw predator curve
ctx.strokeStyle = '#e74c3c';
for (let i = 0; i < predatorHistory.length; i++) {
const x = 50 + (timeHistory[i] / maxTime) * (canvas.width - 100);
const y = canvas.height - 50 - (predatorHistory[i] / maxPredator) * (canvas.height - 100);
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
// Draw current populations
const preyX = 50 + (time / maxTime) * (canvas.width - 100);
const preyY = canvas.height - 50 - (preyPopulation / maxPrey) * (canvas.height - 100);
const predatorX = 50 + (time / maxTime) * (canvas.width - 100);
const predatorY = canvas.height - 50 - (predatorPopulation / maxPredator) * (canvas.height - 100);
// Draw dots
ctx.fillStyle = '#3498db';
ctx.beginPath();
ctx.arc(preyX, preyY, 5, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#e74c3c';
ctx.beginPath();
ctx.arc(predatorX, predatorY, 5, 0, Math.PI * 2);
ctx.fill();
// Draw population values
ctx.fillStyle = '#3498db';
ctx.font = '12px Arial';
ctx.fillText(`Prey: ${preyPopulation.toFixed(0)}`, preyX + 10, preyY - 10);
ctx.fillStyle = '#e74c3c';
ctx.fillText(`Predator: ${predatorPopulation.toFixed(0)}`, predatorX + 10, predatorY - 10);
}
// Reset simulation
function resetSimulation() {
time = 0;
preyHistory = [];
predatorHistory = [];
timeHistory = [];
}
// Animation loop
function animate() {
calculatePopulations();
drawSimulation();
if (time < maxTime) {
requestAnimationFrame(animate);
} else {
// Restart simulation when it completes
resetSimulation();
animate();
}
}
// Initialize event listeners
document.getElementById('preyRate').addEventListener('input', updateParams);
document.getElementById('predationRate').addEventListener('input', updateParams);
document.getElementById('predatorDeathRate').addEventListener('input', updateParams);
document.getElementById('predatorEfficiency').addEventListener('input', updateParams);
// Handle initial population inputs
document.getElementById('initialPrey').addEventListener('input', function() {
const value = parseInt(this.value);
document.getElementById('preyInput').value = value;
preyPopulation = value;
updateValueDisplays();
});
document.getElementById('initialPredator').addEventListener('input', function() {
const value = parseInt(this.value);
document.getElementById('predatorInput').value = value;
predatorPopulation = value;
updateValueDisplays();
});
document.getElementById('preyInput').addEventListener('change', updateInitialPopulations);
document.getElementById('predatorInput').addEventListener('change', updateInitialPopulations);
document.getElementById('resetBtn').addEventListener('click', function() {
resetSimulation();
animate();
});
// Initialize displays
updateValueDisplays();
// Start simulation
animate();
</script>
</body>
</html>