See code on blockbuilder.org/tblondelle/...
Thomas Blondelle, École Centrale de Lyon, janvier 2018
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<svg></svg>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 ,
height = 500 ;
var graph_height = height - margin.top - margin.bottom - 100,
graph_width = width- margin.left - margin.right;
var svg = d3.select("svg")
.attr("width", 960)
.attr("height", 500);
// Set the ranges
var x = d3.scaleLinear().range([0, graph_width]),
y = d3.scaleLinear().range([graph_height, 0]),
color = d3.scaleOrdinal(d3.schemeCategory10),
symbol = d3.symbol().size(50);
d3.csv("iris.csv", function(error, data) {
if (error) throw error;
// Get Regression Data
var xSeries = []
var ySeries = []
data.forEach(function(d) {
xSeries.push(+d.petal_length)
ySeries.push(+d.sepal_length)
});
var leastSquaresCoeff = leastSquares(xSeries, ySeries);
var x1 = x(0),
y1 = leastSquaresCoeff[0] * x1 + leastSquaresCoeff[1],
x2 = x(d3.max(data, function(d) { return d.sepal_length; })),
y2 = leastSquaresCoeff[0] * x2 + leastSquaresCoeff[1];
var trendData = [x1, y1, x2, y2];
// Scale the range of the data
x.domain([0, d3.max(data, function(d) { return d.petal_length; })]);
y.domain([0, d3.max(data, function(d) { return d.sepal_length; })]);
var scales = d3.scaleOrdinal()
.domain(function(d){return d.species})
.range([0, 1, 2]);
// Add title
var title = svg.append("g")
.attr("class", "title")
.attr("transform", "translate(" + 60 + "," +0 + ")");
title.append("text")
.attr("x", 10)
.attr("y", 60)
.text("Longueur de sépale en fonction de la longueur de pétale (en cm)")
.attr("font-family", "sans-serif")
.attr("font-size", "20px")
// Add graph.
var graph = svg.append("g")
.attr("class", 'graph')
.attr("transform", "translate(" + margin.left + "," + +(margin.top + 60) + ")");
graph.selectAll(".dot").data(data).enter()
.append("path")
.attr("class", "dot")
.attr("d", function(d) {
return symbol.type(d3.symbols[ scales(d.species) ])(); })
.attr("transform", function(d,i) {
return "translate(" + x(d.petal_length) + ", " + y(d.sepal_length) + ")"})
.attr("fill", function(d){
return color(d.species)})
// Add the X Axis.
graph.append("g")
.attr("transform", "translate(0," + graph_height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis.
graph.append("g")
.call(d3.axisLeft(y));
// Add regression line
graph.selectAll(".trend").data([trendData]).enter()
.append("line")
.attr("class", "trend")
.attr("x1", function(d) { return x(d[0]) })
.attr("y1", function(d) { return y(d[1]) })
.attr("x2", function(d) { return x(d[2]) })
.attr("y2", function(d) { return y(d[3]) })
.attr('stroke', "red")
});
//https://bl.ocks.org/benvandyke/8459843
// returns slope, intercept and r-square of the line
function leastSquares(xSeries, ySeries) {
var reduceSumFunc = function(prev, cur) { return prev + cur; };
var xBar = xSeries.reduce(reduceSumFunc) * 1.0 / xSeries.length;
var yBar = ySeries.reduce(reduceSumFunc) * 1.0 / ySeries.length;
var ssXX = xSeries.map(function(d) { return Math.pow(d - xBar, 2); })
.reduce(reduceSumFunc);
var ssYY = ySeries.map(function(d) { return Math.pow(d - yBar, 2); })
.reduce(reduceSumFunc);
var ssXY = xSeries.map(function(d, i) { return (d - xBar) * (ySeries[i] - yBar); })
.reduce(reduceSumFunc);
var slope = ssXY / ssXX;
var intercept = yBar - (xBar * slope);
var rSquare = Math.pow(ssXY, 2) / (ssXX * ssYY);
return [slope, intercept, rSquare];
}
</script>
</body>
https://d3js.org/d3.v4.min.js