infinite-agents-public/infinite_variants/infinite_variant_6/example_output/visualization_1.html

361 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Global Temperature Trends - Iteration 1</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.container {
max-width: 1200px;
width: 100%;
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
padding: 40px;
}
h1 {
color: #2d3748;
font-size: 2.5rem;
margin-bottom: 10px;
text-align: center;
}
.subtitle {
color: #718096;
text-align: center;
margin-bottom: 30px;
}
#viz-container {
width: 100%;
height: 500px;
margin-bottom: 30px;
}
.attribution {
background: #f7fafc;
padding: 20px;
border-radius: 10px;
border-left: 4px solid #667eea;
margin-top: 30px;
}
.attribution h3 {
color: #2d3748;
margin-bottom: 10px;
}
.attribution p {
color: #4a5568;
line-height: 1.6;
}
.attribution a {
color: #667eea;
text-decoration: none;
}
.attribution a:hover {
text-decoration: underline;
}
.tooltip {
position: absolute;
background: rgba(0,0,0,0.9);
color: white;
padding: 10px 15px;
border-radius: 5px;
font-size: 14px;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
h1 {
font-size: 1.8rem;
}
#viz-container {
height: 400px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Global Temperature Trends</h1>
<p class="subtitle">Interactive time series visualization with D3.js scales and transitions</p>
<div id="viz-container"></div>
<div class="attribution">
<h3>About This Visualization</h3>
<p><strong>Iteration:</strong> 1 of Example Run</p>
<p><strong>Web Learning Source:</strong> <a href="https://observablehq.com/@d3/learn-d3-scales" target="_blank">D3 Learn - Scales</a></p>
<p><strong>Techniques Applied:</strong></p>
<ul>
<li>Linear scales for mapping data to pixels</li>
<li>Time scales for temporal data</li>
<li>Smooth transitions for visual feedback</li>
</ul>
<p style="margin-top: 10px;"><strong>Data Source:</strong> Simulated climate data (example)</p>
</div>
</div>
<!-- Metadata for state tracking (hidden) -->
<div id="metadata" style="display:none;">
{
"iteration": 1,
"web_source": "https://observablehq.com/@d3/learn-d3-scales",
"techniques_learned": [
"Linear scales for mapping data to pixels",
"Time scales for temporal data",
"Smooth transitions for visual feedback"
],
"data_source": "simulated",
"created": "2025-03-10T14:30:00Z"
}
</div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
/**
* Global Temperature Trends Visualization - Iteration 1
*
* Web Source: https://observablehq.com/@d3/learn-d3-scales
* Techniques Learned:
* 1. Linear scales for mapping data to pixels
* 2. Time scales for temporal data
* 3. Smooth transitions for visual feedback
*
* Data Source: Simulated climate data
* Created: 2025-03-10T14:30:00Z
* Run ID: example
*/
// Generate simulated temperature data
function generateData() {
const data = [];
const startYear = 1880;
const endYear = 2024;
let baseTemp = 13.9; // baseline global average in Celsius
for (let year = startYear; year <= endYear; year++) {
// Simulate warming trend with noise
const yearsSinceStart = year - startYear;
const warming = yearsSinceStart * 0.01; // 0.01°C per year trend
const noise = (Math.random() - 0.5) * 0.3; // random variation
const temp = baseTemp + warming + noise;
data.push({
date: new Date(year, 0, 1),
temperature: temp
});
}
return data;
}
// Create visualization
function createVisualization() {
const container = d3.select('#viz-container');
const containerNode = container.node();
const width = containerNode.clientWidth;
const height = containerNode.clientHeight;
const margin = { top: 40, right: 40, bottom: 60, left: 60 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
// Generate data
const data = generateData();
// Create SVG
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// TECHNIQUE 1: Time scales for temporal data
const xScale = d3.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, innerWidth]);
// TECHNIQUE 1: Linear scales for mapping data to pixels
const yScale = d3.scaleLinear()
.domain([
d3.min(data, d => d.temperature) - 0.5,
d3.max(data, d => d.temperature) + 0.5
])
.range([innerHeight, 0]);
// Create axes
const xAxis = d3.axisBottom(xScale)
.ticks(10)
.tickFormat(d3.timeFormat('%Y'));
const yAxis = d3.axisLeft(yScale)
.ticks(8)
.tickFormat(d => d + '°C');
// Add axes
g.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,${innerHeight})`)
.call(xAxis)
.selectAll('text')
.style('font-size', '12px');
g.append('g')
.attr('class', 'y-axis')
.call(yAxis)
.selectAll('text')
.style('font-size', '12px');
// Add axis labels
g.append('text')
.attr('x', innerWidth / 2)
.attr('y', innerHeight + 45)
.attr('text-anchor', 'middle')
.style('font-size', '14px')
.style('fill', '#4a5568')
.text('Year');
g.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', -innerHeight / 2)
.attr('y', -45)
.attr('text-anchor', 'middle')
.style('font-size', '14px')
.style('fill', '#4a5568')
.text('Temperature (°C)');
// Create line generator
const line = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.temperature))
.curve(d3.curveMonotoneX);
// Add line path with transition (TECHNIQUE 3)
const path = g.append('path')
.datum(data)
.attr('fill', 'none')
.attr('stroke', '#667eea')
.attr('stroke-width', 3)
.attr('d', line);
// TECHNIQUE 3: Smooth transitions for visual feedback
const pathLength = path.node().getTotalLength();
path
.attr('stroke-dasharray', pathLength)
.attr('stroke-dashoffset', pathLength)
.transition()
.duration(2000)
.ease(d3.easeLinear)
.attr('stroke-dashoffset', 0);
// Add dots for data points
const dots = g.selectAll('.dot')
.data(data)
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', d => xScale(d.date))
.attr('cy', d => yScale(d.temperature))
.attr('r', 0)
.attr('fill', '#764ba2')
.style('cursor', 'pointer');
// TECHNIQUE 3: Animate dots appearance
dots.transition()
.delay((d, i) => i * 10)
.duration(300)
.attr('r', 4);
// Add tooltip
const tooltip = d3.select('body').append('div')
.attr('class', 'tooltip');
// Add interactivity
dots
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', 8)
.attr('fill', '#f56565');
tooltip
.style('opacity', 1)
.html(`
<strong>Year:</strong> ${d.date.getFullYear()}<br>
<strong>Temperature:</strong> ${d.temperature.toFixed(2)}°C
`)
.style('left', (event.pageX + 10) + 'px')
.style('top', (event.pageY - 30) + 'px');
})
.on('mouseout', function() {
d3.select(this)
.transition()
.duration(200)
.attr('r', 4)
.attr('fill', '#764ba2');
tooltip.style('opacity', 0);
});
// Add reference line for baseline
const baselineTemp = data[0].temperature;
g.append('line')
.attr('x1', 0)
.attr('x2', innerWidth)
.attr('y1', yScale(baselineTemp))
.attr('y2', yScale(baselineTemp))
.attr('stroke', '#cbd5e0')
.attr('stroke-width', 2)
.attr('stroke-dasharray', '5,5');
g.append('text')
.attr('x', innerWidth - 5)
.attr('y', yScale(baselineTemp) - 10)
.attr('text-anchor', 'end')
.style('font-size', '12px')
.style('fill', '#718096')
.text('Baseline (1880)');
}
// Initialize on load
createVisualization();
// Handle resize
window.addEventListener('resize', () => {
d3.select('#viz-container').selectAll('*').remove();
createVisualization();
});
</script>
</body>
</html>