Skip to content

Instantly share code, notes, and snippets.

@dahtah
Last active September 30, 2017 16:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save dahtah/4731053 to your computer and use it in GitHub Desktop.
Save dahtah/4731053 to your computer and use it in GitHub Desktop.
How to get a significant correlation value by moving just one point around.

Have you ever seen these scatterplots that report a significant correlation between X and Y, but it looks like it's just the one point to the upper-right driving the correlation? Thanks to this interactive tool, you too can do this at home. Click anywhere in the picture, and the red dot will move. The sliding bar displays the resulting correlation coefficient. The grey interval are non-significant values: place the red dot right to get a significant result.

Data are generated from two standard independent gaussian (N=15). Test values are from the asymptotic Fisher transformation test that's on Wikipedia (two-sided, alpha = 5%). Code: R and d3.js.

d3scatterplot = function(svg,data) {
var df=data.df;
var nPix= 420,n=df.length,mar = [40,60,40,40];
var xv = df.map(function(e) { return e.x;}),xRange=expand(d3.extent(xv));
var yv = df.map(function(e) { return e.y;}),yRange=expand(d3.extent(yv));
svg.attr("width", nPix+mar[0]+mar[2])
.attr("height", nPix+mar[1]+mar[3]);
var sg = svg.append("g")
.attr("transform", "translate("
+ mar[0] + ","
+ mar[1] + ")");
var xScale = d3.scale.linear()
.range([0, nPix])
.domain(xRange);
var yScale = d3.scale.linear()
.range([nPix, 0])
.domain(yRange);
drawdots = function()
{
sg.selectAll("circle").remove();
sg.selectAll("circle")
.data(df).enter()
.append("circle")
.attr("cx",function(d) {return xScale(d.x);})
.attr("cy",function(d) {return yScale(d.y);})
.attr("fill",function(d,i) { return (i == (n-1))?"red":"black";})
.attr("id",function(d,i) {return "point" + i})
.attr("r",5);
}
var xAxis = d3.svg.axis().scale(xScale).orient("bottom").ticks(4);
svg.append("g").call(xAxis)
.attr("class", "axis") //Assign "axis" class
.attr("transform","translate(" + mar[0] + "," + (nPix+mar[1]) + ")");
var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(4);
svg.append("g").call(yAxis)
.attr("class", "axis") //Assign "axis" class
.attr("transform","translate(" + mar[0] + "," + (mar[3]) + ")");
drawdots();
correlation_meter(df,data.ci);
svg.on("click",function(el)
{
//Get mouse position
var mP=d3.mouse(this);
//Mouse position to data coordinates
var nx = xScale.invert(mP[0]-mar[0]),ny = yScale.invert(mP[1]-mar[1]);
//Change datapoint accordingly
df[n-1].x = nx;
df[n-1].y = ny;
correlation_meter(df,data.ci);
drawdots();
});
}
correlation_meter = function(df,ci)
{
var svg = d3.select('svg'),nPix=100;
var xv = df.map(function(e) { return e.x;});
var yv = df.map(function(e) { return e.y;});
d3.select("#meter").remove();
var sg = svg.append("g")
.attr("id","meter")
.attr("transform", "translate("
+ 100 + ","
+ 20 + ")");
var yScale = d3.scale.linear()
.range([nPix, 0])
.domain([-1,1]);
var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(4);
sg.append("g").call(yAxis)
.attr("class", "axis") //Assign "axis" class
var cf = corcoef(xv,yv);
// sg.append("circle")
// .attr("cx",10)
// .attr("cy",yScale(cf))
// .attr("r",4)
// .attr("fill","blue");
sg.append("line")
.attr("x1",5)
.attr("x2",15)
.attr("y1",yScale(cf))
.attr("y2",yScale(cf))
.attr("id","ciline")
.attr("stroke-width","3px")
.attr("stroke", "red")
.attr("fill","black");
sg.append("line")
.attr("x1",1)
.attr("x2",1)
.attr("y1",yScale(ci[0]))
.attr("y2",yScale(ci[1]))
.attr("id","ciline")
.attr("stroke-width","5px")
.attr("stroke", "grey")
.attr("fill","black");
if (cf < ci[0] | cf > ci[1])
{
msg ="p < .05"
sg.append("text")
.attr("x",30)
.attr("y",50)
.attr("font-size",28)
.text(msg);
}
}
d3.json("data.json", function(data) {
var svg = d3.select("#d3plot").append("svg")
.attr("width","100%")
.attr("height","100%");
d3scatterplot(svg,data);
});
variance = function(u)
{
var n=u.length,alpha = (n/(n-1));
var r = (d3.mean(u.map(function(v) { return v*v;})) - Math.pow(d3.mean(u),2));
return alpha*r;
}
//Subtract mean and divide by sd.
standardise = function(u)
{
var m = d3.mean(u), s=Math.sqrt(variance(u));
return u.map(function(v) { return (v-m)/s;});
}
//Compute Pearson's correlation between u and v
corcoef = function(u,v)
{
var us = standardise(u),vs = standardise(v),n=u.length;
return (1/(n-1))*d3.sum(us.mult(vs));
}
Array.prototype.enorm = function () {
return Math.sqrt(this.reduce(function(prev,cur) { return prev + cur*cur; },0));
}
Array.prototype.add = function (b) {
var s = Array(this.length);
for (var ind = 0; ind < this.length; ind++)
{
if (typeof(b)=="number")
{
s[ind] = this[ind]+ b;
}
else
{
s[ind] = this[ind]+ b[ind];
}
}
return s;
};
Array.prototype.mult = function (b) {
var s = Array(this.length);
for (var ind = 0; ind < this.length; ind++)
{
if (typeof(b)=="number")
{
s[ind] = this[ind]* b;
}
else
{
s[ind] = this[ind]* b[ind];
}
}
return s;
};
Array.prototype.max = function () {
return Math.max.apply(Math, this);
};
//Used to expand slightly the plotting window
expand = function(r)
{
var d = r[1] - r[0],alpha=.8;
return r.add([-alpha*d, alpha*d]);
}
{
"df": [
{
"x": 0.22011,
"y": -0.028382
},
{
"x": -0.50125,
"y": 0.71029
},
{
"x": -0.86128,
"y": -0.68656
},
{
"x": 0.21666,
"y": -0.24793
},
{
"x": 0.83934,
"y": 0.97039
},
{
"x": -0.81477,
"y": -1.4286
},
{
"x": 0.50696,
"y": 0.48366
},
{
"x": 2.3821,
"y": -0.6622
},
{
"x": -0.4799,
"y": -1.1952
},
{
"x": 0.2055,
"y": -0.93525
},
{
"x": 0.47511,
"y": 0.84901
},
{
"x": -0.61064,
"y": -0.08118
},
{
"x": -0.14239,
"y": -1.2393
},
{
"x": 0.63065,
"y": 0.012554
},
{
"x": 0.94607,
"y": -0.0036405
}
],
"ci": [ -0.51226, 0.51226 ]
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="http://d3js.org/d3.v2.js"></script>
<script src="correlation.js"></script>
<style>
.axis,
.frame {
shape-rendering: crispEdges;
}
.axis line {
stroke: #00F;
stroke-width: 2px;
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis path {
stroke: #00F;
stroke-width: 2px;
stroke: black;
fill: none;
}
.axis text {
font-family: sans-serif;
font-size: 10px;
}
.ghost {
fill: blue;
fill-opacity: 0;
}
.label {
font-size: 12px;
color: blue;
}
.datapoint {
r: 5;
fill: blue;
fill-opacity: .5;
}
#d3plot {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<div id="d3plot" class="d3-scatter-output"> </div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment