// // Set-up // // map variables to our dataset const xVariable = 'GDP_perCapita'; const yVariable = 'lifeExpectancy'; const rVariable = 'GDP'; const idVariable = 'CountryCode'; const groupByVariable = 'Region'; const tooltipVariable = 'Country'; // set label text const xLabel = 'GDP per capita [US $] - Note the logarithmic scale'; const yLabel = 'Life expectancy'; // vanilla JS window width and height const wV = window; const dV = document; const eV = dV.documentElement; const gV = dV.getElementsByTagName('body')[0]; const xV = wV.innerWidth || eV.clientWidth || gV.clientWidth; const yV = wV.innerHeight || eV.clientHeight || gV.clientHeight; // Quick fix for resizing some things for mobile-ish viewers const mobileScreen = (xV < 500); // Scatterplot const margin = { left: 30, top: 20, right: 20, bottom: 20 }; const chartWidth = document.getElementById('chart').offsetWidth; const width = Math.min(chartWidth, 800) - margin.left - margin.right; const height = width * 2 / 3; // const maxDistanceFromPoint = 50; const svg = d3.select('svg') .attr('width', (width + margin.left + margin.right)) .attr('height', (height + margin.top + margin.bottom)); const wrapper = svg.append('g').attr('class', 'chordWrapper') .attr('transform', `translate(${margin.left}, ${margin.top})`); // // Initialize Axes & Scales // const opacityCircles = 0.7; // Set the color for each region const color = d3.scaleOrdinal() .range([ '#EFB605', '#E58903', '#E01A25', '#C20049', '#991C71', '#66489F', '#2074A0', '#10A66E', '#7EB852' ]); d3.json('data.json', (error, data) => { // get values for color domain from the data const uniqueGroupByVariables = d3.set(data, d => d[groupByVariable]) .values() .sort((a, b) => a > b); // ascending alphabetical sort // set the domain of the color scale // we use this later for the legend color.domain(uniqueGroupByVariables); // Set the new x axis range const xScale = d3.scaleLog() .range([0, width]) .domain([100, 2e5]); // I prefer this exact scale over the true range and then using "nice" // .domain(d3.extent(data, function(d) { return d[xVariable]; })) // .nice(); // Set new x-axis const xAxis = d3.axisBottom() .ticks(10) .tickFormat(d => // Difficult function to create better ticks xScale.tickFormat((mobileScreen ? 4 : 8), e => { const prefix = d3.format(",.0s"); return `$${prefix(e)}`; })(d)) .scale(xScale); // Append the x-axis wrapper.append('g') .attr('class', 'x axis') .attr('transform', `translate(${0},${height})`) .call(xAxis); // Set the new y axis range const yScale = d3.scaleLinear() .range([height, 0]) .domain(d3.extent(data, d => d[yVariable])) .nice(); const yAxis = d3.axisLeft() .ticks(6) // Set rough # of ticks .scale(yScale); // Append the y-axis wrapper.append('g') .attr('class', 'y axis') .attr('transform', `translate(${0}, ${0})`) .call(yAxis); // Scale for the bubble size const rScale = d3.scaleSqrt() .range([ mobileScreen ? 1 : 2, mobileScreen ? 10 : 16 ]) .domain(d3.extent(data, d => d[rVariable])); // // Scatterplot Circles // // Initiate a group element for the circles const circleGroup = wrapper.append('g') .attr('class', 'circleWrapper'); // Place the country circles circleGroup.selectAll('marks') .data(data.sort((a, b) => b[rVariable] > a[rVariable])) // Sort so the biggest circles are below .enter().append('circle') .attr('class', (d) => `marks ${d[idVariable]}`) .style('opacity', opacityCircles) .style('fill', d => color(d[groupByVariable])) .attr('cx', d => xScale(d[xVariable])) .attr('cy', d => yScale(d[yVariable])) .attr('r', d => rScale(d[rVariable])); // // Tooltips // const tip = d3.tip() .attr('class', 'd3-tip') .html(d => { return `