metreex-analysis.js
/**
 * Adds a Guassian Error Ellipse representing 90% confidence intervals for both axes of a bivariate scatterplot.
 * @param {Array} projectionData 2-D array with 2 columns representing the X and Y axes and N rows representing the data along each axis
 * @param {Object} parent A d3 selection containing only the SVG element which the ellipse should be added to
 * @param {Object} xaxis d3 ScaleLinear element representing the x axis
 * @param {Object} yaxis d3 ScaleLinear element representing the y axis
 * @param strokeColor Color [returned by a d3 scaleOrdinal] to apply to the ellipse's stroke
 * @param {Object} treebankInfo Must contain the author, and can optionally include the title, and section of the treebank. Title and section are necessary if drawing ellipses for each treebank.
 * @param tooltip HTML div for the tooltip to be drawn in (Optional)
 */
Adds a Guassian Error Ellipse representing 90% confidence intervals for both axes of a bivariate scatterplot.
Adds a Guassian Error Ellipse representing 90% confidence intervals for both axes of a bivariate scatterplot .
function addErrorEllipse(projectionData, parent, xaxis, yaxis, strokeColor, treebankInfo, tooltip){
    var projXdata = [], projYdata = [];
    if (projectionData.length === 1){
        projectionData.push(projectionData[0]); 
        return;
    }
    else if (projectionData.length === 0){
        console.log(treebankInfo.author + " " + treebankInfo.title + " " + treebankInfo.section +  " encountered an error - no projection data");
        return;
    }
    projectionData.forEach(function (elem) {
        projXdata.push(elem[0]);
        projYdata.push(elem[1]);
    });
    var projXstdev = d3.deviation(projectionData, function(elem){return elem[0]}),
        projYstdev = d3.deviation(projectionData, function(elem){return elem[1]}),
        projectionCovMat = computeCovariance(projectionData),
        projectionEigenVal = computeEigendecomposition(projectionCovMat),
        ellipseScale = Math.sqrt(2.705543454096032), 
        maxEigen = getIndexOfMax(projectionEigenVal.eigVals),
        minEigen = getIndexOfMin(projectionEigenVal.eigVals),
        maxScale = Math.sqrt(Math.abs(projectionEigenVal.eigVals[maxEigen])) * ellipseScale,
        minScale = Math.sqrt(Math.abs(projectionEigenVal.eigVals[minEigen])) * ellipseScale,
        ellRX = projXstdev > projYstdev ? maxScale : minScale,
        ellRY = projXstdev < projYstdev ? maxScale : minScale,
        dominantEigenVec = projectionEigenVal.eigVecs[maxEigen],
        rot = Math.atan2(dominantEigenVec[1], dominantEigenVec[0]);
    rot = (rot < 0) ? (rot + 2 * math.PI) : rot;
    var projXextent = d3.extent(projectionData, function(elem){return elem[0];}),
        projYextent = d3.extent(projectionData, function(elem){return elem[1];}),
        tooltipText = "Author: " + treebankInfo.author;
    if (treebankInfo.title !== undefined) { tooltipText += "<br>Title: " + treebankInfo.title; }
    else {treebankInfo.title = "";}
    if (treebankInfo.section !== undefined) { tooltipText += "<br>Section: " + treebankInfo.section; }
    var ellipseClass = "PCA-ellipse " + treebankInfo.title.toString().toLowerCase().replace(/ /g,"") + " " + treebankInfo.author;
    if (treebankInfo.section !== undefined) { ellipseClass += " sec" + treebankInfo.section.toString().replace(/\./g,"\\."); }
    var newEllipse = parent.append("ellipse")
        .attr("class", ellipseClass)
        .attr("rx", Math.abs(xaxis(projXextent[0] + ellRX) - xaxis(projXextent[0])))
        .attr("ry", Math.abs(yaxis(projYextent[0] + ellRY) - yaxis(projYextent[0])))
        .style("stroke", strokeColor)
        .attr("transform", "translate(" + xaxis(d3.mean(projectionData, function(elem){return elem[0];})) + "," + yaxis(d3.mean(projectionData, function(elem){return elem[1];})) +
            ") rotate(" + (rot * 180 / math.PI) + ")");
    if (tooltip !== undefined) {
        var selector = ".PCA-point." + treebankInfo.author.toString().replace(/ /g,".");
        if (treebankInfo.title !== undefined && treebankInfo.title !== "") selector += "." + treebankInfo.title.toString().toLowerCase().replace(/ /g,"");
        if (treebankInfo.section !== undefined) selector += ".sec" + treebankInfo.section.toString().replace(/\./g,"\\.");
        newEllipse
            .on("mouseover", function () {
                d3.selectAll(".PCA-point")
                    .style("opacity", ".2");
                d3.selectAll(".PCA-ellipse")
                    .style("opacity", ".2");
                d3.select(selector.replace(/PCA-point/,"PCA-ellipse"))
                    .style("opacity","1");
                tooltip.html(tooltipText)
                    .style("left", (d3.event.pageX + 10) + "px")
                    .style("top", (d3.event.pageY + 10) + "px")
                    .style("display", "inline");
                d3.selectAll(selector)
                    .style("opacity","1")
                    .each(function () {
                        this.parentNode.appendChild(this);
                    });
            })
            .on("mouseout", function () {
                d3.selectAll(".PCA-point")
                    .style("opacity", "1");
                d3.selectAll(".PCA-ellipse")
                    .style("opacity", "1");
                tooltip.style("display", "none");
                d3.selectAll(selector)
                    .each(function () {
                        this.parentNode.insertBefore(this, d3.select(".PCA-ellipse").node());
                    });
            });
    }
}
function addErrorEllipse ( projectionData , parent , xaxis , yaxis , strokeColor , treebankInfo , tooltip ) { var projXdata = [ ] , projYdata = [ ] ; if ( projectionData . length === 1 ) { projectionData . push ( projectionData [ 0 ] ) ; return ; } else if ( projectionData . length === 0 ) { console . log ( treebankInfo . author + " " + treebankInfo . title + " " + treebankInfo . section + " encountered an error - no projection data" ) ; return ; } projectionData . forEach ( function ( elem ) { projXdata . push ( elem [ 0 ] ) ; projYdata . push ( elem [ 1 ] ) ; } ) ; var projXstdev = d3 . deviation ( projectionData , function ( elem ) { return elem [ 0 ] } ) , projYstdev = d3 . deviation ( projectionData , function ( elem ) { return elem [ 1 ] } ) , projectionCovMat = computeCovariance ( projectionData ) , projectionEigenVal = computeEigendecomposition ( projectionCovMat ) , ellipseScale = Math . sqrt ( 2.705543454096032 ) , maxEigen = getIndexOfMax ( projectionEigenVal . eigVals ) , minEigen = getIndexOfMin ( projectionEigenVal . eigVals ) , maxScale = Math . sqrt ( Math . abs ( projectionEigenVal . eigVals [ maxEigen ] ) ) * ellipseScale , minScale = Math . sqrt ( Math . abs ( projectionEigenVal . eigVals [ minEigen ] ) ) * ellipseScale , ellRX = projXstdev > projYstdev ? maxScale : minScale , ellRY = projXstdev < projYstdev ? maxScale : minScale , dominantEigenVec = projectionEigenVal . eigVecs [ maxEigen ] , rot = Math . atan2 ( dominantEigenVec [ 1 ] , dominantEigenVec [ 0 ] ) ; rot = ( rot < 0 ) ? ( rot + 2 * math . PI ) : rot ; var projXextent = d3 . extent ( projectionData , function ( elem ) { return elem [ 0 ] ; } ) , projYextent = d3 . extent ( projectionData , function ( elem ) { return elem [ 1 ] ; } ) , tooltipText = "Author: " + treebankInfo . author ; if ( treebankInfo . title !== undefined ) { tooltipText += "<br>Title: " + treebankInfo . title ; } else { treebankInfo . title = "" ; } if ( treebankInfo . section !== undefined ) { tooltipText += "<br>Section: " + treebankInfo . section ; } var ellipseClass = "PCA-ellipse " + treebankInfo . title . toString ( ) . toLowerCase ( ) . replace ( / / g , "" ) + " " + treebankInfo . author ; if ( treebankInfo . section !== undefined ) { ellipseClass += " sec" + treebankInfo . section . toString ( ) . replace ( / \. / g , "\\." ) ; } var newEllipse = parent . append ( "ellipse" ) . attr ( "class" , ellipseClass ) . attr ( "rx" , Math . abs ( xaxis ( projXextent [ 0 ] + ellRX ) - xaxis ( projXextent [ 0 ] ) ) ) . attr ( "ry" , Math . abs ( yaxis ( projYextent [ 0 ] + ellRY ) - yaxis ( projYextent [ 0 ] ) ) ) . style ( "stroke" , strokeColor ) . attr ( "transform" , "translate(" + xaxis ( d3 . mean ( projectionData , function ( elem ) { return elem [ 0 ] ; } ) ) + "," + yaxis ( d3 . mean ( projectionData , function ( elem ) { return elem [ 1 ] ; } ) ) + ") rotate(" + ( rot * 180 / math . PI ) + ")" ) ; if ( tooltip !== undefined ) { var selector = ".PCA-point." + treebankInfo . author . toString ( ) . replace ( / / g , "." ) ; if ( treebankInfo . title !== undefined && treebankInfo . title !== "" ) selector += "." + treebankInfo . title . toString ( ) . toLowerCase ( ) . replace ( / / g , "" ) ; if ( treebankInfo . section !== undefined ) selector += ".sec" + treebankInfo . section . toString ( ) . replace ( / \. / g , "\\." ) ; newEllipse . on ( "mouseover" , function ( ) { d3 . selectAll ( ".PCA-point" ) . style ( "opacity" , ".2" ) ; d3 . selectAll ( ".PCA-ellipse" ) . style ( "opacity" , ".2" ) ; d3 . select ( selector . replace ( / PCA-point / , "PCA-ellipse" ) ) . style ( "opacity" , "1" ) ; tooltip . html ( tooltipText ) . style ( "left" , ( d3 . event . pageX + 10 ) + "px" ) . style ( "top" , ( d3 . event . pageY + 10 ) + "px" ) . style ( "display" , "inline" ) ; d3 . selectAll ( selector ) . style ( "opacity" , "1" ) . each ( function ( ) { this . parentNode . appendChild ( this ) ; } ) ; } ) . on ( "mouseout" , function ( ) { d3 . selectAll ( ".PCA-point" ) . style ( "opacity" , "1" ) ; d3 . selectAll ( ".PCA-ellipse" ) . style ( "opacity" , "1" ) ; tooltip . style ( "display" , "none" ) ; d3 . selectAll ( selector ) . each ( function ( ) { this . parentNode . insertBefore ( this , d3 . select ( ".PCA-ellipse" ) . node ( ) ) ; } ) ; } ) ; } }
Adds a Guassian Error Ellipse representing 90% confidence intervals for both axes of a bivariate scatterplot.
Adds a Guassian Error Ellipse representing 90% confidence intervals for both axes of a bivariate scatterplot .
//Could return here instead to save on calculations. //http://onlinelibrary.wiley.com/doi/10.1002/0471998303.app4/pdf 1 degree of freedom, p=0.9