worlwide-data / index.html
fdaudens's picture
fdaudens HF Staff
Add 2 files
91fb5c4 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive GDP vs Life Expectancy Scatterplot</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f7fa;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
padding: 30px;
}
h1 {
text-align: center;
color: #2c3e50;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #7f8c8d;
margin-bottom: 30px;
font-size: 1.1em;
}
.chart-container {
position: relative;
margin-top: 20px;
}
.tooltip {
position: absolute;
padding: 10px;
background: rgba(255, 255, 255, 0.95);
border: 1px solid #ddd;
border-radius: 5px;
pointer-events: none;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
font-size: 14px;
max-width: 200px;
z-index: 10;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip h3 {
margin: 0 0 5px 0;
color: #2c3e50;
}
.tooltip p {
margin: 5px 0;
}
.legend {
margin-top: 20px;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
margin: 0 15px 10px 15px;
}
.legend-color {
width: 15px;
height: 15px;
border-radius: 50%;
margin-right: 8px;
}
.controls {
display: flex;
justify-content: center;
margin-bottom: 20px;
gap: 15px;
flex-wrap: wrap;
}
.control-group {
display: flex;
align-items: center;
background: #f8f9fa;
padding: 8px 15px;
border-radius: 30px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
}
.control-group label {
margin-right: 10px;
font-weight: 500;
color: #555;
}
select {
padding: 6px 12px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: white;
cursor: pointer;
}
.reset-btn {
background-color: #3498db;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
transition: background-color 0.2s;
}
.reset-btn:hover {
background-color: #2980b9;
}
.axis-label {
font-size: 14px;
font-weight: 500;
fill: #555;
}
.grid line {
stroke: #e0e0e0;
stroke-dasharray: 2,2;
}
.grid .domain {
stroke: none;
}
.continent-filter {
display: flex;
gap: 10px;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 20px;
}
.continent-btn {
padding: 6px 12px;
border-radius: 20px;
border: 1px solid #ddd;
background-color: white;
cursor: pointer;
transition: all 0.2s;
font-size: 14px;
}
.continent-btn:hover {
transform: translateY(-2px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.continent-btn.active {
border-color: transparent;
color: white;
font-weight: 500;
}
</style>
</head>
<body>
<div class="container">
<h1><i class="fas fa-globe-americas"></i> Global Development Indicators</h1>
<p class="subtitle">Explore the relationship between GDP, Life Expectancy, and Population across countries</p>
<div class="controls">
<div class="control-group">
<label for="x-scale">X-Axis Scale:</label>
<select id="x-scale">
<option value="linear">Linear</option>
<option value="log">Logarithmic</option>
</select>
</div>
<div class="control-group">
<label for="y-scale">Y-Axis Scale:</label>
<select id="y-scale">
<option value="linear">Linear</option>
<option value="log">Logarithmic</option>
</select>
</div>
<button class="reset-btn" id="reset-zoom">
<i class="fas fa-search-minus"></i> Reset Zoom
</button>
</div>
<div class="continent-filter">
<button class="continent-btn active" data-continent="all">All Continents</button>
<button class="continent-btn" data-continent="Africa" style="background-color: #FF6384;">Africa</button>
<button class="continent-btn" data-continent="Asia" style="background-color: #36A2EB;">Asia</button>
<button class="continent-btn" data-continent="Europe" style="background-color: #FFCE56;">Europe</button>
<button class="continent-btn" data-continent="North America" style="background-color: #4BC0C0;">North America</button>
<button class="continent-btn" data-continent="South America" style="background-color: #9966FF;">South America</button>
<button class="continent-btn" data-continent="Oceania" style="background-color: #FF9F40;">Oceania</button>
</div>
<div class="chart-container">
<div id="scatterplot"></div>
<div class="tooltip" id="tooltip"></div>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background-color: #FF6384;"></div>
<span>Africa</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #36A2EB;"></div>
<span>Asia</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #FFCE56;"></div>
<span>Europe</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #4BC0C0;"></div>
<span>North America</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #9966FF;"></div>
<span>South America</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #FF9F40;"></div>
<span>Oceania</span>
</div>
</div>
</div>
<script>
// Generate dummy data
function generateDummyData() {
const continents = ['Africa', 'Asia', 'Europe', 'North America', 'South America', 'Oceania'];
const continentColors = {
'Africa': '#FF6384',
'Asia': '#36A2EB',
'Europe': '#FFCE56',
'North America': '#4BC0C0',
'South America': '#9966FF',
'Oceania': '#FF9F40'
};
const countryNames = {
'Africa': ['Nigeria', 'Egypt', 'South Africa', 'Kenya', 'Ethiopia', 'Ghana', 'Morocco', 'Tanzania'],
'Asia': ['China', 'India', 'Japan', 'South Korea', 'Indonesia', 'Thailand', 'Vietnam', 'Philippines'],
'Europe': ['Germany', 'France', 'UK', 'Italy', 'Spain', 'Poland', 'Netherlands', 'Sweden'],
'North America': ['USA', 'Canada', 'Mexico', 'Cuba', 'Guatemala', 'Panama', 'Costa Rica', 'Jamaica'],
'South America': ['Brazil', 'Argentina', 'Colombia', 'Chile', 'Peru', 'Venezuela', 'Ecuador', 'Bolivia'],
'Oceania': ['Australia', 'New Zealand', 'Fiji', 'Papua New Guinea', 'Samoa', 'Tonga', 'Vanuatu']
};
let data = [];
continents.forEach(continent => {
countryNames[continent].forEach(country => {
// Generate random but somewhat realistic values
const gdpPerCapita = continent === 'Africa' ?
Math.random() * 5000 + 500 :
continent === 'Asia' ?
Math.random() * 15000 + 3000 :
continent === 'Europe' ?
Math.random() * 30000 + 20000 :
continent === 'North America' ?
Math.random() * 40000 + 10000 :
continent === 'South America' ?
Math.random() * 15000 + 5000 :
Math.random() * 30000 + 10000; // Oceania
const lifeExpectancy = continent === 'Africa' ?
Math.random() * 10 + 55 :
continent === 'Asia' ?
Math.random() * 10 + 65 :
continent === 'Europe' ?
Math.random() * 5 + 75 :
continent === 'North America' ?
Math.random() * 5 + 75 :
continent === 'South America' ?
Math.random() * 5 + 70 :
Math.random() * 5 + 75; // Oceania
const population = continent === 'Africa' ?
Math.random() * 100000000 + 10000000 :
continent === 'Asia' ?
Math.random() * 1000000000 + 100000000 :
continent === 'Europe' ?
Math.random() * 50000000 + 5000000 :
continent === 'North America' ?
Math.random() * 200000000 + 10000000 :
continent === 'South America' ?
Math.random() * 100000000 + 10000000 :
Math.random() * 20000000 + 1000000; // Oceania
data.push({
country: country,
continent: continent,
gdpPerCapita: gdpPerCapita,
lifeExpectancy: lifeExpectancy,
population: population,
color: continentColors[continent]
});
});
});
return data;
}
// Main visualization function
function createScatterplot(data) {
// Set dimensions and margins
const margin = {top: 60, right: 80, bottom: 80, left: 80};
const width = 900 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;
// Create SVG
const svg = d3.select("#scatterplot")
.html("") // Clear previous content
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Add clip path to prevent circles from appearing outside the chart area
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// Create scales (initial linear scales)
let xScale = d3.scaleLinear()
.domain([d3.min(data, d => d.gdpPerCapita) * 0.9, d3.max(data, d => d.gdpPerCapita) * 1.1])
.range([0, width])
.nice();
let yScale = d3.scaleLinear()
.domain([d3.min(data, d => d.lifeExpectancy) * 0.9, d3.max(data, d => d.lifeExpectancy) * 1.1])
.range([height, 0])
.nice();
// Create size scale for bubbles
const sizeScale = d3.scaleSqrt()
.domain([0, d3.max(data, d => d.population)])
.range([3, 30]);
// Add grid lines
svg.append("g")
.attr("class", "grid")
.call(d3.axisLeft(yScale)
.tickSize(-width)
.tickFormat("")
);
svg.append("g")
.attr("class", "grid")
.call(d3.axisBottom(xScale)
.tickSize(-height)
.tickFormat("")
);
// Add axes
const xAxis = svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale));
const yAxis = svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
// Add axis labels
svg.append("text")
.attr("class", "axis-label")
.attr("x", width / 2)
.attr("y", height + margin.bottom - 20)
.attr("text-anchor", "middle")
.text("GDP per Capita (USD)");
svg.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -margin.left + 20)
.attr("text-anchor", "middle")
.text("Life Expectancy (years)");
// Add chart title
svg.append("text")
.attr("x", width / 2)
.attr("y", -20)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.style("font-weight", "bold")
.text("GDP vs Life Expectancy by Country");
// Create zoom behavior
const zoom = d3.zoom()
.scaleExtent([0.5, 8])
.on("zoom", zoomed);
// Apply zoom to the SVG
d3.select("#scatterplot svg")
.call(zoom)
.on("dblclick.zoom", null); // Disable double-click zoom
// Store original scales for reset
const originalXScale = xScale.copy();
const originalYScale = yScale.copy();
// Zoom function
function zoomed(event) {
const newXScale = event.transform.rescaleX(originalXScale);
const newYScale = event.transform.rescaleY(originalYScale);
xScale = newXScale;
yScale = newYScale;
updateChart();
}
// Reset zoom button
document.getElementById("reset-zoom").addEventListener("click", function() {
d3.select("#scatterplot svg")
.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity);
xScale = originalXScale;
yScale = originalYScale;
updateChart();
});
// Tooltip
const tooltip = d3.select("#tooltip");
// Create circles for each data point
let circles = svg.append("g")
.attr("clip-path", "url(#clip)")
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d.gdpPerCapita))
.attr("cy", d => yScale(d.lifeExpectancy))
.attr("r", d => sizeScale(d.population))
.attr("fill", d => d.color)
.attr("opacity", 0.7)
.attr("stroke", "#fff")
.attr("stroke-width", 1)
.on("mouseover", function(event, d) {
d3.select(this)
.attr("opacity", 1)
.attr("stroke-width", 2);
tooltip.transition()
.duration(200)
.style("opacity", 0.9);
tooltip.html(`
<h3>${d.country}</h3>
<p><strong>Continent:</strong> ${d.continent}</p>
<p><strong>GDP per capita:</strong> $${d3.format(",.0f")(d.gdpPerCapita)}</p>
<p><strong>Life expectancy:</strong> ${d3.format(".1f")(d.lifeExpectancy)} years</p>
<p><strong>Population:</strong> ${d3.format(",.0f")(d.population)}</p>
`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px");
})
.on("mouseout", function() {
d3.select(this)
.attr("opacity", 0.7)
.attr("stroke-width", 1);
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
// Update chart function
function updateChart() {
// Update axes
svg.select(".x.axis")
.transition()
.duration(750)
.call(d3.axisBottom(xScale));
svg.select(".y.axis")
.transition()
.duration(750)
.call(d3.axisLeft(yScale));
// Update grid lines
svg.select(".grid.x")
.transition()
.duration(750)
.call(d3.axisBottom(xScale)
.tickSize(-height)
.tickFormat("")
);
svg.select(".grid.y")
.transition()
.duration(750)
.call(d3.axisLeft(yScale)
.tickSize(-width)
.tickFormat("")
);
// Update circles
circles
.transition()
.duration(750)
.attr("cx", d => xScale(d.gdpPerCapita))
.attr("cy", d => yScale(d.lifeExpectancy));
}
// Scale type toggle
document.getElementById("x-scale").addEventListener("change", function() {
const scaleType = this.value;
const currentDomain = xScale.domain();
if (scaleType === "log") {
xScale = d3.scaleLog()
.domain([Math.max(1, currentDomain[0]), currentDomain[1]])
.range([0, width])
.nice();
} else {
xScale = d3.scaleLinear()
.domain(currentDomain)
.range([0, width])
.nice();
}
updateChart();
});
document.getElementById("y-scale").addEventListener("change", function() {
const scaleType = this.value;
const currentDomain = yScale.domain();
if (scaleType === "log") {
yScale = d3.scaleLog()
.domain([Math.max(1, currentDomain[0]), currentDomain[1]])
.range([height, 0])
.nice();
} else {
yScale = d3.scaleLinear()
.domain(currentDomain)
.range([height, 0])
.nice();
}
updateChart();
});
// Continent filter buttons
document.querySelectorAll(".continent-btn").forEach(btn => {
btn.addEventListener("click", function() {
const continent = this.dataset.continent;
// Update button states
document.querySelectorAll(".continent-btn").forEach(b => {
b.classList.remove("active");
});
this.classList.add("active");
// Filter data
let filteredData = data;
if (continent !== "all") {
filteredData = data.filter(d => d.continent === continent);
}
// Update circles
circles = svg.selectAll("circle")
.data(filteredData, d => d.country);
circles.exit()
.transition()
.duration(500)
.attr("r", 0)
.remove();
circles.enter()
.append("circle")
.attr("cx", d => xScale(d.gdpPerCapita))
.attr("cy", d => yScale(d.lifeExpectancy))
.attr("r", 0)
.attr("fill", d => d.color)
.attr("opacity", 0.7)
.attr("stroke", "#fff")
.attr("stroke-width", 1)
.on("mouseover", function(event, d) {
d3.select(this)
.attr("opacity", 1)
.attr("stroke-width", 2);
tooltip.transition()
.duration(200)
.style("opacity", 0.9);
tooltip.html(`
<h3>${d.country}</h3>
<p><strong>Continent:</strong> ${d.continent}</p>
<p><strong>GDP per capita:</strong> $${d3.format(",.0f")(d.gdpPerCapita)}</p>
<p><strong>Life expectancy:</strong> ${d3.format(".1f")(d.lifeExpectancy)} years</p>
<p><strong>Population:</strong> ${d3.format(",.0f")(d.population)}</p>
`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 10) + "px");
})
.on("mouseout", function() {
d3.select(this)
.attr("opacity", 0.7)
.attr("stroke-width", 1);
tooltip.transition()
.duration(500)
.style("opacity", 0);
})
.transition()
.duration(500)
.attr("r", d => sizeScale(d.population));
circles
.transition()
.duration(500)
.attr("r", d => sizeScale(d.population));
});
});
}
// Initialize the chart
document.addEventListener("DOMContentLoaded", function() {
const data = generateDummyData();
createScatterplot(data);
// For future CSV loading
window.loadCSVData = function(csvData) {
// Process CSV data here
// Format should be: country,continent,gdpPerCapita,lifeExpectancy,population
createScatterplot(csvData);
};
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
</html>