source: Dev/branches/jQueryUI/client/d3/src/chart/qq.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

File size: 6.6 KB
Line 
1// Based on http://vis.stanford.edu/protovis/ex/qqplot.html
2d3.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
231function 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
239function d3_chart_qqX(d) {
240  return d.x;
241}
242
243function d3_chart_qqY(d) {
244  return d.y;
245}
Note: See TracBrowser for help on using the repository browser.