// package.json { "name": "scatterplot-vizhub", "version": "1.0.0", "description": "Reusable scatter plot visualization", "main": "index.js", "dependencies": { "d3": "^6.7.0" } } // index.js d3.csv("https://gist.githubusercontent.com/Sahith100/e8b647a92ea960a8eb85d09a935d3bda/raw/eedd0d9249681ef1e253af7dc3abfa6bcdbd7bae/sga.csv").then(data => { data.forEach(d => { d.sepal_width = +d.sepal_width; d.sepal_length = +d.sepal_length; }); scatterPlot("#scatterplot", data, "sepal_width", "sepal_length"); }); // scatterplot.js function scatterPlot(container, data, xKey, yKey) { const width = 500, height = 400, margin = { top: 20, right: 30, bottom: 40, left: 50 }; const svg = d3.select(container).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})`); const xScale = d3.scaleLinear() .domain(d3.extent(data, d => d[xKey])) .range([0, width]); const yScale = d3.scaleLinear() .domain(d3.extent(data, d => d[yKey])) .range([height, 0]); svg.append("g") .attr("transform", `translate(0,${height})`) .call(d3.axisBottom(xScale)); svg.append("g") .call(d3.axisLeft(yScale)); svg.selectAll("circle") .data(data) .enter().append("circle") .attr("cx", d => xScale(d[xKey])) .attr("cy", d => yScale(d[yKey])) .attr("r", 5) .attr("fill", "blue"); svg.append("text") .attr("x", width / 2) .attr("y", height + margin.bottom - 5) .style("text-anchor", "middle") .text("Sepal Width"); svg.append("text") .attr("transform", "rotate(-90)") .attr("x", -height / 2) .attr("y", -margin.left + 15) .style("text-anchor", "middle") .text("Sepal Length"); } /* styles.css */ body { font-family: Arial, sans-serif; } svg { display: block; margin: auto; } circle { stroke: black; }