1 vq.ScatterPlot = function() { 2 vq.Vis.call(this); 3 // private variables 4 5 this.height(300); // defaults 6 this.width(700); // defaults 7 this.vertical_padding(20); 8 this.horizontal_padding(30); 9 this.selectedProbesetId(''); 10 11 }; 12 vq.ScatterPlot.prototype = pv.extend(vq.Vis); 13 14 vq.ScatterPlot.prototype 15 .property('selectedProbesetId'); 16 17 // sets default variables based on the options 18 vq.ScatterPlot.prototype._setOptionDefaults = function(options) { 19 // PUBLIC OPTIONS 20 // padding 21 if (options.selectedProbesetId) { 22 this._selectedProbesetId = options.selectedProbesetId; 23 } 24 25 if (options.height != null) { 26 this.height(options.height); 27 } 28 29 if (options.width != null) { 30 this.width(options.width); 31 } 32 33 if (options.container != null) { 34 this.container(options.container); 35 } 36 37 if (options.vertical_padding != null) { 38 this.vertical_padding(options.vertical_padding); 39 } 40 41 if (options.horizontal_padding != null) { 42 this.horizontal_padding(options.horizontal_padding); 43 } 44 }; 45 46 vq.ScatterPlot.prototype.onProbesetSelect = function(probesetId) { 47 this.selectedProbesetId = probesetId; 48 }; 49 50 51 vq.ScatterPlot.prototype.setRegression = function(obj) { 52 this.data._regression = obj || 'none'; 53 this._render(); 54 }; 55 56 vq.ScatterPlot.prototype.draw = function(data) { 57 this.data = new vq.models.ScatterPlotData(data); 58 59 if (!this.data.isDataReady()) { return;} 60 61 this._setOptionDefaults(this.data); 62 this._visHeight = this.height() - ( 2 * this.vertical_padding()); 63 this._visWidth = this.width() - ( 2 * this.horizontal_padding()); 64 65 66 this._render(); 67 }; 68 69 vq.ScatterPlot.prototype._render = function() { 70 var that = this; 71 var div = this.container(); 72 73 function trans() { 74 var t = this.transform().invert(); 75 var w = vis.width(); 76 var h = vis.height(); 77 var halfX = (showMaxX - showMinX) / 2, halfY = (showMaxY - showMinY) / 2, 78 centerX = showMaxX - halfX, centerY = showMaxY - halfY, 79 scaleX = 2 * halfX / (w), scaleY = 2 * halfY / h; 80 81 xScale.domain(t.x * scaleX - (halfX) + centerX, centerX + (w * t.k + t.x) * scaleX - halfX); 82 yScale.domain(-1 * ( h * t.k + (t.y)) * scaleY + halfY + centerY, -1 * ( t.y) * scaleY + halfY + centerY); 83 84 vis.render(); 85 } 86 87 var dataObj = this.data; 88 89 var x = dataObj.COLUMNID.x; 90 var y = dataObj.COLUMNID.y; 91 var value = dataObj.COLUMNID.value; 92 93 var data_array = dataObj.data; 94 var minX = data_array.reduce(function(previous, current) { 95 return (current[x] != null) && current[x] < previous ? current[x] : previous; 96 }, 999999); 97 var maxX = data_array.reduce(function(previous, current) { 98 return (current[x] != null) && current[x] > previous ? current[x] : previous; 99 }, -999999); 100 var minY = data_array.reduce(function(previous, current) { 101 return (current[y] != null) && current[y] < previous ? current[y] : previous; 102 }, 999999); 103 var maxY = data_array.reduce(function(previous, current) { 104 return (current[y] != null) && current[y] > previous ? current[y] : previous; 105 }, -999999); 106 107 //expand plot around highest/lowest values 108 var showMinX = minX - (Math.abs(maxX - minX) * 0.03); 109 var showMaxX = maxX + (Math.abs(maxX - minX) * 0.03); 110 var showMinY = minY - (Math.abs(maxY - minY) * 0.03); 111 var showMaxY = maxY + (Math.abs(maxY - minY) * 0.03); 112 113 //start protovis code 114 var xScale = pv.Scale.linear(showMinX, showMaxX).range(0, this.width()); 115 var yScale = pv.Scale.linear(showMinY, showMaxY).range(0, this.height()); 116 117 //regression line! 118 var regress = dataObj._regression; 119 if (regress=='linear') { 120 var valid_data = data_array.filter(function(d, e, f) { 121 return (d[y] && d[x]); 122 }), 123 sum_x = pv.sum(valid_data, function(d) { 124 return d[x]; 125 }), 126 sum_y = pv.sum(valid_data, function(d) { 127 return d[y]; 128 }), 129 sum_x2 = pv.sum(valid_data, function(d) { 130 return d[x] * d[x]; 131 }), 132 //sum_y2 = pv.sum(valid_data, function(d) { return d[y] * d[y]; }), 133 sum_xy = pv.sum(valid_data, function(d) { 134 return d[x] * d[y]; 135 }), 136 slope = ((valid_data.length * sum_xy) - (sum_x * sum_y)) / ((valid_data.length * sum_x2) - (sum_x * sum_x)); 137 138 var intercept = (sum_y - slope * sum_x) / valid_data.length; 139 } 140 var line_minX = showMinX * 0.95; 141 var line_maxX = showMaxX * 1.05; 142 var line_maxY = slope * line_maxX + intercept; 143 var line_minY = slope * line_minX + intercept; 144 145 var lineArray = pv.Scale.linear(line_minX, line_maxX).range(line_minY, line_maxY); 146 147 //identify selected Probeset, if passed in. 148 var selectedProbesetId; 149 150 if (this._selectedProbesetId) { 151 selectedProbesetId = this._selectedProbesetId; 152 } 153 154 var vis = new pv.Panel() 155 .width(this.width()) 156 .height(this.height()) 157 .bottom(this.vertical_padding()) 158 .left(this.horizontal_padding()) 159 .right(this.horizontal_padding()) 160 .top(this.vertical_padding()) 161 .strokeStyle("#aaa") 162 .events("all") 163 .event("mousemove", pv.Behavior.point()) 164 .canvas(div); 165 166 //y-axis ticks 167 vis.add(pv.Rule) 168 .data(function() { 169 return yScale.ticks() 170 }) 171 .bottom(yScale) 172 .strokeStyle(function(d) { 173 return d ? "#ccc" : "#999" 174 }) 175 .anchor("left").add(pv.Label) 176 .text(yScale.tickFormat); 177 178 //y-axis label 179 vis.add(pv.Label) 180 .text(dataObj.COLUMNLABEL.y) 181 .font(that.font) 182 .textAlign("center") 183 .left(-24) 184 .bottom(this.height() / 2) 185 .textAngle(-1 * Math.PI / 2); 186 187 //x-axis ticks 188 vis.add(pv.Rule) 189 .data(function() { 190 return xScale.ticks() 191 }) 192 .left(xScale) 193 .strokeStyle(function(d) { 194 return d ? "#ccc" : "#999" 195 }) 196 .anchor("bottom").add(pv.Label) 197 .text(xScale.tickFormat); 198 199 //x-axis label 200 vis.add(pv.Label) 201 .text(dataObj.COLUMNLABEL.x) 202 .font(that.font) 203 .textAlign("center") 204 .bottom(-30) 205 .left(this.width() / 2); 206 207 var panel = vis.add(pv.Panel) 208 .events('all') 209 .overflow("hidden"); 210 211 if (!isNaN(slope) && regress =='linear') { 212 panel.add(pv.Line) 213 .data([line_minX, line_maxX]) 214 .left(function(d) { 215 return xScale(d); 216 }) 217 .bottom(function(d) { 218 return yScale(lineArray(d)); 219 }) 220 .strokeStyle("#0b0"); 221 } 222 223 var strokeStyle = function(data) { 224 return pv.color(dataObj._strokeStyle(data)); 225 }; 226 var fillStyle = function(data) { 227 return pv.color(dataObj._fillStyle(data)); 228 }; 229 panel.add(pv.Dot) 230 .def("active", -1) 231 .data(data_array) 232 .left(function(d) { 233 return xScale(d[x]); 234 }) 235 .bottom(function(d) { 236 return yScale(d[y]) 237 }) 238 .strokeStyle(strokeStyle) 239 .fillStyle(fillStyle) 240 .radius(dataObj._radius) 241 .shape(dataObj._shape) 242 .event("point", function() { 243 return this.active(this.index).parent; 244 }) 245 .event("unpoint", function() { 246 return this.active(-1).parent; 247 }) 248 .event('click', dataObj._notifier) 249 .anchor("right").add(pv.Label) 250 .visible(function() { 251 return this.anchorTarget().active() == this.index; 252 }) 253 .text(function(d) { 254 return dataObj.COLUMNLABEL.value + " " + d[value]; 255 }); 256 257 258 /* Use an invisible panel to capture pan & zoom events. */ 259 vis.add(pv.Panel) 260 .left(0) 261 .bottom(0) 262 .events("all") 263 .event("mousedown", pv.Behavior.pan()) 264 .event("mousewheel", pv.Behavior.zoom()) 265 .event("pan", trans) 266 .event("zoom", trans); 267 268 /** Update the x- and y-scale domains per the new transform. */ 269 270 vis.render(); 271 272 }; 273 274 275 vq.models.ScatterPlotData = function(data) { 276 vq.models.VisData.call(this, data); 277 this.setDataModel(); 278 if (this.getDataType() == 'vq.models.ScatterPlotData') { 279 this._build_data(this.getContents()); 280 } else { 281 console.warn('Unrecognized JSON object. Expected vq.models.ScatterPlotData object.'); 282 } 283 }; 284 vq.models.ScatterPlotData.prototype = pv.extend(vq.models.VisData); 285 286 287 vq.models.ScatterPlotData.prototype.setDataModel = function () { 288 this._dataModel = [ 289 {label: 'width', id: 'PLOT.width', cast : Number, defaultValue: 400}, 290 {label: 'height', id: 'PLOT.height', cast : Number, defaultValue: 300}, 291 {label : 'container', id:'PLOT.container', optional : true}, 292 {label: 'vertical_padding', id: 'PLOT.vertical_padding', cast : Number, defaultValue: 20}, 293 {label: 'horizontal_padding', id: 'PLOT.horizontal_padding',cast : Number, defaultValue:30}, 294 {label : 'data', id: 'data_array', defaultValue : [] }, 295 {label : 'COLUMNID.x', id: 'xcolumnid',cast : String, defaultValue : 'X'}, 296 {label : 'COLUMNID.y', id: 'ycolumnid',cast : String, defaultValue : 'Y'}, 297 {label : 'COLUMNID.value', id: 'valuecolumnid',cast : String, defaultValue : 'VALUE'}, 298 {label : 'COLUMNLABEL.x', id: 'xcolumnlabel',cast : String, defaultValue : ''}, 299 {label : 'COLUMNLABEL.y', id: 'ycolumnlabel',cast : String, defaultValue : ''}, 300 {label : 'COLUMNLABEL.value', id: 'valuecolumnlabel',cast : String, defaultValue : ''}, 301 {label : 'COLUMNLABEL.value', id: 'valuecolumnlabel',cast : String, defaultValue : ''}, 302 {label : 'tooltipItems', id: 'tooltip_items', defaultValue : { 303 X : 'X', Y : 'Y', Value : 'VALUE' } }, 304 {label : '_fillStyle', id: 'fill_style',cast :vq.utils.VisUtils.wrapProperty, 305 defaultValue : function() { 306 return pv.color('steelblue').alpha(0.2); 307 }}, 308 {label : '_strokeStyle', id: 'stroke_style', 309 cast :vq.utils.VisUtils.wrapProperty, defaultValue : function() { 310 return 'steelblue'; 311 }}, 312 {label : '_radius', id: 'radius',cast :vq.utils.VisUtils.wrapProperty, defaultValue : function() { 313 return 2; 314 }}, 315 {label : '_shape', id: 'shape',cast : vq.utils.VisUtils.wrapProperty, defaultValue : function() { 316 return 'dot'; 317 }}, 318 {label : '_regression', id: 'regression',cast :String, defaultValue : 'none'}, 319 {label : '_notifier', id: 'notifier', cast : Function, defaultValue : function() { 320 return null; 321 }} 322 ]; 323 }; 324 325 vq.models.ScatterPlotData.prototype._build_data = function(data) { 326 this._processData(data); 327 328 if (this.COLUMNLABEL.x == '') this.COLUMNLABEL.x = this.COLUMNID.x; 329 if (this.COLUMNLABEL.y == '') this.COLUMNLABEL.y = this.COLUMNID.y; 330 if (this.COLUMNLABEL.value == '') this.COLUMNLABEL.value = this.COLUMNID.value; 331 332 if (this.data.length > 0) this.setDataReady(true); 333 }; 334