randRange(-80, 80) / 20
randRange(-5, 5)
function(x) { return SLOPE * x + INTERCEPT }
((SLOPE < 0 ? -1 : 1) * 11 - INTERCEPT) / SLOPE
((SLOPE < 0 ? 1 : -1) * 11 - INTERCEPT) / SLOPE
function(x, low, high) {
return (x < low) ? low : (x > high) ? high : x;
}
random() + 0.5
(BOTTOM < -11) ? -11 : BOTTOM
(TOP > 11) ? 11 : TOP
sortNumbers((function() {
var range = (RIGHT - LEFT) / 20;
return _.map(shuffle(_.range(-8, 9), 9), function(x) {
return x * range;
});
})())
function(a) {
// make sure the points are unique in a
for (var i = 0; i < a.length; ++i) {
for (var j = i + 1; j < a.length; ++j) {
if (_.isEqual(a[i], a[j])) {
a.splice(j, 1);
--j;
}
}
}
return a;
}
function(low, high) {
return random() * (high - low) + low;
}
atan2(SLOPE, 1) + PI / 2
[cos(ANG), sin(ANG)]
[]
UNIQARRAYS(_.map(XS, function(x, index) {
// calculate the sum of the offsets so far
var total = _.reduce(TOTALOFFSET, function(sum, num) {
return sum + num;
}, 0);
var offset;
if (index < 2 || index > 6) {
// make sure the first two and last
// two points are on the same side
offset = RANDRANGE(OFFSET/2, OFFSET);
} else if (total < 0) {
// if the offset is negative, choose less
// negative numbers
offset = RANDRANGE(-OFFSET - total, OFFSET);
} else {
// if it is positive, choose less
//positive numbers
offset = RANDRANGE(-OFFSET, OFFSET - total);
}
// store this offset
TOTALOFFSET.push(offset);
// calculate the rounded point created by this offset
return [BOUND(round(x + PERP[0] * offset), -9, 9),
BOUND(round(FUNC(x) + PERP[1] * offset), -9, 9)];
}))
(function() {
// calculate the linear square regression
// line for our points
var xAve = _.reduce(POINTS, function(sum, pt) {
return sum + pt[0];
}, 0) / POINTS.length;
var yAve = _.reduce(POINTS, function(sum, pt) {
return sum + pt[1];
}, 0) / POINTS.length;
var xi2 = _.reduce(POINTS, function(sum, pt) {
return sum + pow(pt[0], 2);
}, 0);
var xiyi = _.reduce(POINTS, function(sum, pt) {
return sum + pt[0] * pt[1];
}, 0);
var realIntercept = (yAve * xi2 - xAve * xiyi) /
(xi2 - POINTS.length * pow(xAve, 2));
var realSlope = (xiyi - POINTS.length * xAve * yAve) /
(xi2 - POINTS.length * pow(xAve, 2));
return [realSlope, realIntercept];
})()
{}
function(slope, intercept) {
var low = _.first(POINTS), high = _.last(POINTS);
var slopeadd = 1 / REALSLOPE + REALSLOPE;
lowx = (1 / REALSLOPE * low[0] + low[1] - REALINTERCEPT) /
slopeadd;
highx = (1 / REALSLOPE * high[0] + high[1] - REALINTERCEPT) /
slopeadd;
var lowfunc = function(x) {
return -1 / REALSLOPE * (x - low[0]) + low[1];
};
var highfunc = function(x) {
return -1 / REALSLOPE * (x - high[0]) + high[1];
};
lowIntersectx = (1 / REALSLOPE * low[0] +
low[1] - intercept) /
(slope + 1 / REALSLOPE);
highIntersectx = (1 / REALSLOPE * high[0] +
high[1] - intercept) /
(slope + 1 / REALSLOPE);
// the differences between the least squares line and the
// given line, at the highest and lowest points
var lowDiff = sqrt(pow(lowfunc(lowx) -
lowfunc(lowIntersectx), 2) +
pow(lowx - lowIntersectx, 2));
var highDiff = sqrt(pow(highfunc(highx) -
highfunc(highIntersectx), 2) +
pow(highx - highIntersectx, 2));
// whether or not each of the points are above or below
// the given line
var updown = _.map(POINTS, function(pt) {
var x = pt[0], y = pt[1],
est = slope * x + intercept;
return y >= est ? 1 : -1;
});
// sort and reverse-sort updown
var updownSorted = sortNumbers(updown);
var updownReversed = updownSorted.slice(0).reverse();
// ensure:
// all the points are not up, ..., up, down, ..., down
return !_.isEqual(updown, updownSorted) &&
// all the points are not down, ..., down, up, ..., up
!_.isEqual(updown, updownReversed) &&
// one point is above/below
_.include(updown, 1) &&
_.include(updown, -1) &&
// the differences are between some proportion
// of the offset
lowDiff < 1.3 * OFFSET &&
highDiff < 1.3 * OFFSET;
}
Find the line of best fit,
or mark that there is no linear correlation.
graphInit({
range: 11,
scale: 20,
axisArrows: "<->",
tickStep: 1,
labelStep: 1,
gridOpacity: 0.05,
axisOpacity: 0.2,
tickOpacity: 0.4,
labelOpacity: 0.5
});
addMouseLayer();
// add the points
_.each(POINTS, function(pt) {
circle(pt, 0.2, { fill: "black" });
});
// add our movable line
graph.pointA = addMovablePoint({
coord: [-5, 5],
snapX: 0.5,
snapY: 0.5,
normalStyle: {
stroke: KhanUtil.BLUE,
fill: KhanUtil.BLUE
}
});
graph.pointB = addMovablePoint({
coord: [5, 5],
snapX: 0.5,
snapY: 0.5,
normalStyle: {
stroke: KhanUtil.BLUE,
fill: KhanUtil.BLUE
}
});
graph.line1 = addMovableLineSegment({
pointA: graph.pointA,
pointZ: graph.pointB,
fixed: true,
extendLine: true
});
// A and B can't be in the same place
graph.pointA.onMove = function(x, y) {
return (x != graph.pointB.coord[0] ||
y != graph.pointB.coord[1]);
};
graph.pointB.onMove = function(x, y) {
return (x != graph.pointA.coord[0] ||
y != graph.pointA.coord[1]);
};
graph.pointA.toFront();
graph.pointB.toFront();
var shown = false;
graph.showLine = function() {
graph.pointA.visibleShape.show();
graph.pointA.mouseTarget.show();
graph.pointB.visibleShape.show();
graph.pointB.mouseTarget.show();
graph.line1.visibleLine.show();
};
graph.hideLine = function() {
graph.pointA.visibleShape.hide();
graph.pointA.mouseTarget.hide();
graph.pointB.visibleShape.hide();
graph.pointB.mouseTarget.hide();
graph.line1.visibleLine.hide();
};
// show the true least square regression line
graph.showSolution = function() {
if (shown) {
return;
} else {
shown = true;
}
var roundToHalf = function(x) {
return round(x * 2) / 2;
};
var realFunc = function(x) {
return REALSLOPE * x + REALINTERCEPT;
};
$("html, body").animate({
scrollTop: $(".question").offset().top
}, {
duration: 500,
easing: "swing",
complete: function() {
line([-11, realFunc(-11)],
[11, realFunc(11)],
{ stroke: ORANGE, opacity: 0 })
.animate({ opacity: 1 }, 750);
}
});
};
GRAPH = graph;
Move the line on the graph to show a best fit line,
if it exists.
[
GRAPH.pointA.coord, GRAPH.pointB.coord,
$("input[name='linear']:checked").attr("id")
]
if (_.isEqual(guess, [[-5, 5], [5, 5], "exists"])) {
return "";
}
// Check that the right checkbox is checked
if (guess[2] !== "exists") {
return false;
}
var slope = (guess[1][1] - guess[0][1]) /
(guess[1][0] - guess[0][0]);
var intercept = slope * -guess[0][0] + guess[0][1];
// Validate the line
return VALIDATOR(slope, intercept);
GRAPH.pointA.setCoord(guess[0]);
GRAPH.pointB.setCoord(guess[1]);
GRAPH.line1.transform(true);
$("#"+guess[2]).attr('checked', 'checked');
The line of best fit is the line that best approximates
the data points.
There are three main criteria to use when finding a good
best fit line.
First, make sure that your line passes through the points,
and does not lie completely above or below the points.
init({ range: [[-5, 5], [-5, 5]], scale: [20, 20] });
circle([-2, -3], 0.2, { fill: "black" });
circle([ 0, -1], 0.2, { fill: "black" });
circle([-1, 1], 0.2, { fill: "black" });
circle([ 1, 1], 0.2, { fill: "black" });
circle([ 0, 2], 0.2, { fill: "black" });
line([-5, -4], [5, -3], { stroke: BLUE });
label([0, 4], $._("Bad"), "center", false)
.css("color", "red")
.css("font-size", "20px");
init({ range: [[-5, 5], [-5, 5]], scale: [20, 20] });
circle([-2, -3], 0.2, { fill: "black" });
circle([ 0, -1], 0.2, { fill: "black" });
circle([-1, 1], 0.2, { fill: "black" });
circle([ 1, 1], 0.2, { fill: "black" });
circle([ 0, 2], 0.2, { fill: "black" });
line([-5, -2.5], [5, -1.5], { stroke: BLUE });
label([0, 4], $._("Okay"), "center", false)
.css("color", "orange")
.css("font-size", "20px");
Next, make sure that your line alternates between
passing above and then below points, and doesn't simply
go above some points and then below the rest.
init({ range: [[-5, 5], [-5, 5]], scale: [20, 20] });
circle([-2, -3], 0.2, { fill: "black" });
circle([ 0, -1], 0.2, { fill: "black" });
circle([-1, 1], 0.2, { fill: "black" });
circle([ 1, 1], 0.2, { fill: "black" });
circle([ 0, 2], 0.2, { fill: "black" });
line([-5, -2.5], [5, -1.5], { stroke: BLUE });
label([0, 4], $._("Okay"), "center", false)
.css("color", "orange")
.css("font-size", "20px");
init({ range: [[-5, 5], [-5, 5]], scale: [20, 20] });
circle([-2, -3], 0.2, { fill: "black" });
circle([ 0, -1], 0.2, { fill: "black" });
circle([-1, 1], 0.2, { fill: "black" });
circle([ 1, 1], 0.2, { fill: "black" });
circle([ 0, 2], 0.2, { fill: "black" });
line([-5, -3.5], [3, 5], { stroke: BLUE });
label([0, 4], $._("Better"), "center", false)
.css("color", "#8EEB00")
.css("font-size", "20px");
Last, make sure that the line goes through the middle
of all the points, so that it is close to all of
the points.
init({ range: [[-5, 5], [-5, 5]], scale: [20, 20] });
circle([-2, -3], 0.2, { fill: "black" });
circle([ 0, -1], 0.2, { fill: "black" });
circle([-1, 1], 0.2, { fill: "black" });
circle([ 1, 1], 0.2, { fill: "black" });
circle([ 0, 2], 0.2, { fill: "black" });
line([-5, -3.5], [3, 5], { stroke: BLUE });
label([0, 4], $._("Better"), "center", false)
.css("color", "#9FEE00")
.css("font-size", "20px");
init({ range: [[-5, 5], [-5, 5]], scale: [20, 20] });
circle([-2, -3], 0.2, { fill: "black" });
circle([ 0, -1], 0.2, { fill: "black" });
circle([-1, 1], 0.2, { fill: "black" });
circle([ 1, 1], 0.2, { fill: "black" });
circle([ 0, 2], 0.2, { fill: "black" });
line([-4, -5], [3, 5], { stroke: BLUE });
label([0, 4], $._("Good"), "center", false)
.css("color", "#00C322")
.css("font-size", "20px");
There are several lines that satisfy this.
Click here
to show one of them.