toolkit/exemples/couple/javascript/d3/src/chart/qq.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 // Based on http://vis.stanford.edu/protovis/ex/qqplot.html
       
     2 d3.chart.qq = function() {
       
     3   var width = 1,
       
     4       height = 1,
       
     5       duration = 0,
       
     6       domain = null,
       
     7       tickFormat = null,
       
     8       n = 100,
       
     9       x = d3_chart_qqX,
       
    10       y = d3_chart_qqY;
       
    11 
       
    12   // For each small multiple…
       
    13   function qq(g) {
       
    14     g.each(function(d, i) {
       
    15       var g = d3.select(this),
       
    16           qx = d3_chart_qqQuantiles(n, x.call(this, d, i)),
       
    17           qy = d3_chart_qqQuantiles(n, y.call(this, d, i)),
       
    18           xd = domain && domain.call(this, d, i) || [d3.min(qx), d3.max(qx)], // new x-domain
       
    19           yd = domain && domain.call(this, d, i) || [d3.min(qy), d3.max(qy)], // new y-domain
       
    20           x0, // old x-scale
       
    21           y0; // old y-scale
       
    22 
       
    23       // Compute the new x-scale.
       
    24       var x1 = d3.scale.linear()
       
    25           .domain(xd)
       
    26           .range([0, width]);
       
    27 
       
    28       // Compute the new y-scale.
       
    29       var y1 = d3.scale.linear()
       
    30           .domain(yd)
       
    31           .range([height, 0]);
       
    32 
       
    33       // Retrieve the old scales, if this is an update.
       
    34       if (this.__chart__) {
       
    35         x0 = this.__chart__.x;
       
    36         y0 = this.__chart__.y;
       
    37       } else {
       
    38         x0 = d3.scale.linear().domain([0, Infinity]).range(x1.range());
       
    39         y0 = d3.scale.linear().domain([0, Infinity]).range(y1.range());
       
    40       }
       
    41 
       
    42       // Stash the new scales.
       
    43       this.__chart__ = {x: x1, y: y1};
       
    44 
       
    45       // Update diagonal line.
       
    46       var diagonal = g.selectAll("line.diagonal")
       
    47           .data([null]);
       
    48 
       
    49       diagonal.enter().append("svg:line")
       
    50           .attr("class", "diagonal")
       
    51           .attr("x1", x1(yd[0]))
       
    52           .attr("y1", y1(xd[0]))
       
    53           .attr("x2", x1(yd[1]))
       
    54           .attr("y2", y1(xd[1]));
       
    55 
       
    56       diagonal.transition()
       
    57           .duration(duration)
       
    58           .attr("x1", x1(yd[0]))
       
    59           .attr("y1", y1(xd[0]))
       
    60           .attr("x2", x1(yd[1]))
       
    61           .attr("y2", y1(xd[1]));
       
    62 
       
    63       // Update quantile plots.
       
    64       var circle = g.selectAll("circle")
       
    65           .data(d3.range(n).map(function(i) {
       
    66             return {x: qx[i], y: qy[i]};
       
    67           }));
       
    68 
       
    69       circle.enter().append("svg:circle")
       
    70           .attr("class", "quantile")
       
    71           .attr("r", 4.5)
       
    72           .attr("cx", function(d) { return x0(d.x); })
       
    73           .attr("cy", function(d) { return y0(d.y); })
       
    74           .style("opacity", 1e-6)
       
    75         .transition()
       
    76           .duration(duration)
       
    77           .attr("cx", function(d) { return x1(d.x); })
       
    78           .attr("cy", function(d) { return y1(d.y); })
       
    79           .style("opacity", 1);
       
    80 
       
    81       circle.transition()
       
    82           .duration(duration)
       
    83           .attr("cx", function(d) { return x1(d.x); })
       
    84           .attr("cy", function(d) { return y1(d.y); })
       
    85           .style("opacity", 1);
       
    86 
       
    87       circle.exit().transition()
       
    88           .duration(duration)
       
    89           .attr("cx", function(d) { return x1(d.x); })
       
    90           .attr("cy", function(d) { return y1(d.y); })
       
    91           .style("opacity", 1e-6)
       
    92           .remove();
       
    93 
       
    94       var xformat = tickFormat || x1.tickFormat(4),
       
    95           yformat = tickFormat || y1.tickFormat(4),
       
    96           tx = function(d) { return "translate(" + x1(d) + "," + height + ")"; },
       
    97           ty = function(d) { return "translate(0," + y1(d) + ")"; };
       
    98 
       
    99       // Update x-ticks.
       
   100       var xtick = g.selectAll("g.x.tick")
       
   101           .data(x1.ticks(4), function(d) {
       
   102             return this.textContent || xformat(d);
       
   103           });
       
   104 
       
   105       var xtickEnter = xtick.enter().append("svg:g")
       
   106           .attr("class", "x tick")
       
   107           .attr("transform", function(d) { return "translate(" + x0(d) + "," + height + ")"; })
       
   108           .style("opacity", 1e-6);
       
   109 
       
   110       xtickEnter.append("svg:line")
       
   111           .attr("y1", 0)
       
   112           .attr("y2", -6);
       
   113 
       
   114       xtickEnter.append("svg:text")
       
   115           .attr("text-anchor", "middle")
       
   116           .attr("dy", "1em")
       
   117           .text(xformat);
       
   118 
       
   119       // Transition the entering ticks to the new scale, x1.
       
   120       xtickEnter.transition()
       
   121           .duration(duration)
       
   122           .attr("transform", tx)
       
   123           .style("opacity", 1);
       
   124 
       
   125       // Transition the updating ticks to the new scale, x1.
       
   126       xtick.transition()
       
   127           .duration(duration)
       
   128           .attr("transform", tx)
       
   129           .style("opacity", 1);
       
   130 
       
   131       // Transition the exiting ticks to the new scale, x1.
       
   132       xtick.exit().transition()
       
   133           .duration(duration)
       
   134           .attr("transform", tx)
       
   135           .style("opacity", 1e-6)
       
   136           .remove();
       
   137 
       
   138       // Update ticks.
       
   139       var ytick = g.selectAll("g.y.tick")
       
   140           .data(y1.ticks(4), function(d) {
       
   141             return this.textContent || yformat(d);
       
   142           });
       
   143 
       
   144       var ytickEnter = ytick.enter().append("svg:g")
       
   145           .attr("class", "y tick")
       
   146           .attr("transform", function(d) { return "translate(0," + y0(d) + ")"; })
       
   147           .style("opacity", 1e-6);
       
   148 
       
   149       ytickEnter.append("svg:line")
       
   150           .attr("x1", 0)
       
   151           .attr("x2", 6);
       
   152 
       
   153       ytickEnter.append("svg:text")
       
   154           .attr("text-anchor", "end")
       
   155           .attr("dx", "-.5em")
       
   156           .attr("dy", ".3em")
       
   157           .text(yformat);
       
   158 
       
   159       // Transition the entering ticks to the new scale, y1.
       
   160       ytickEnter.transition()
       
   161           .duration(duration)
       
   162           .attr("transform", ty)
       
   163           .style("opacity", 1);
       
   164 
       
   165       // Transition the updating ticks to the new scale, y1.
       
   166       ytick.transition()
       
   167           .duration(duration)
       
   168           .attr("transform", ty)
       
   169           .style("opacity", 1);
       
   170 
       
   171       // Transition the exiting ticks to the new scale, y1.
       
   172       ytick.exit().transition()
       
   173           .duration(duration)
       
   174           .attr("transform", ty)
       
   175           .style("opacity", 1e-6)
       
   176           .remove();
       
   177     });
       
   178   }
       
   179 
       
   180   qq.width = function(x) {
       
   181     if (!arguments.length) return width;
       
   182     width = x;
       
   183     return qq;
       
   184   };
       
   185 
       
   186   qq.height = function(x) {
       
   187     if (!arguments.length) return height;
       
   188     height = x;
       
   189     return qq;
       
   190   };
       
   191 
       
   192   qq.duration = function(x) {
       
   193     if (!arguments.length) return duration;
       
   194     duration = x;
       
   195     return qq;
       
   196   };
       
   197 
       
   198   qq.domain = function(x) {
       
   199     if (!arguments.length) return domain;
       
   200     domain = x == null ? x : d3.functor(x);
       
   201     return qq;
       
   202   };
       
   203 
       
   204   qq.count = function(z) {
       
   205     if (!arguments.length) return n;
       
   206     n = z;
       
   207     return qq;
       
   208   };
       
   209 
       
   210   qq.x = function(z) {
       
   211     if (!arguments.length) return x;
       
   212     x = z;
       
   213     return qq;
       
   214   };
       
   215 
       
   216   qq.y = function(z) {
       
   217     if (!arguments.length) return y;
       
   218     y = z;
       
   219     return qq;
       
   220   };
       
   221 
       
   222   qq.tickFormat = function(x) {
       
   223     if (!arguments.length) return tickFormat;
       
   224     tickFormat = x;
       
   225     return qq;
       
   226   };
       
   227 
       
   228   return qq;
       
   229 };
       
   230 
       
   231 function d3_chart_qqQuantiles(n, values) {
       
   232   var m = values.length - 1;
       
   233   values = values.slice().sort(d3.ascending);
       
   234   return d3.range(n).map(function(i) {
       
   235     return values[~~(i * m / n)];
       
   236   });
       
   237 }
       
   238 
       
   239 function d3_chart_qqX(d) {
       
   240   return d.x;
       
   241 }
       
   242 
       
   243 function d3_chart_qqY(d) {
       
   244   return d.y;
       
   245 }