1 2 3 //intialize with var data ={DATATYPE : "vq.models.FlexPlotData", CONTENTS : {DATAARRAY : data_array} }; 4 // notifier = function(x,dx) where x = position within scroll bar range, dx = total length of window in scale of scroll bar 5 6 //draw with draw (data ={DATATYPE : "vq.models.FlexPlotData", {DATAARRAY : data_array} } 7 // and options = {plotHeight: xx, plotWidth : xx, verticalPadding: xx, 8 // horizontalPadding : xx , max_x_axis_value: xx, min_x_axis_value: xx, 9 // maxRange: xx, minRange: xx, dblclick_notifier : function(x,dx), 10 // fixedWindowWidth: xx, scaleMultiplier : xx, interval : xx, font : "fontname"} 11 //note dblclick_notifer is the last listed option. This can be used to create a "zoom" effect by re-instanstiating the scroll bar with new parameters. 12 13 14 vq.ChromaVis = function() { 15 vq.Vis.call(this); 16 17 //set option variables to useful values before options are set. 18 this.height(500); // defaults 19 this.width(500); // defaults 20 this.vertical_padding(30); 21 this.horizontal_padding(30); 22 this.max_x_axis_value(11); 23 this.min_x_axis_value(0); 24 this.context_height(50); 25 this.max_y_axis_value(1); 26 this.min_y_axis_value(1); 27 this.max_y(1); 28 this.min_y(1); 29 this.uuid(vq.utils.VisUtils.guid()); 30 31 }; 32 33 vq.ChromaVis.prototype = pv.extend(vq.Vis); 34 35 vq.ChromaVis.prototype 36 .property('uuid',String) 37 .property('max_x_axis_value',Number) 38 .property('min_x_axis_value',Number) 39 .property('max_y_axis_value',Number) 40 .property('min_y_axis_value',Number) 41 .property('max_y',Number) 42 .property('min_y',Number) 43 .property('auto_scale_y',Boolean) 44 .property('auto_scale_x',Boolean) 45 .property('auto_update_scale_y',Boolean) 46 .property('context_height',Number); 47 48 vq.ChromaVis.prototype.slaveTo = function(master_id) { 49 var that = this; 50 var slave_x = true, slave_y = true; 51 if (arguments.length == 3) { slave_x = arguments[1]; slave_y=arguments[2];} 52 this.slaveX = slave_x; 53 this.slaveY = slave_y; 54 if (!this.windowChangeHandler) this.windowChangeHandler = {}; 55 this.windowChangeHandler[master_id] = function(obj) {that.windowchange(obj);}; 56 vq.events.Dispatcher.addListener('chromavis_windowchange',master_id,that.windowChangeHandler[master_id]); 57 }; 58 59 vq.ChromaVis.prototype.unSlaveFrom =function(master_id) { 60 var that =this; 61 if (!that.windowChangeHandler || !that.windowChangeHandler[master_id]) { return;} 62 vq.events.Dispatcher.removeListener('chromavis_windowchange',master_id,that.windowChangeHandler[master_id]); 63 }; 64 65 vq.ChromaVis.prototype.windowchange = function(window_obj) { 66 this.slaveRenderX = this.slaveX; 67 this.slaveRenderY = this.slaveY; 68 if (this.slaveRenderX) this.posX.domain(window_obj.pos.x.min,window_obj.pos.x.max); 69 if (this.slaveRenderY) this._bl_data.yScale.domain(window_obj.pos.y.min,window_obj.pos.y.max); 70 this.drawPanel.render(); 71 this.slaveRenderX = false; 72 this.slaveRenderY = false; 73 }; 74 75 vq.ChromaVis.prototype._setOptionDefaults = function(options) { 76 77 if (options.max_x_axis_value != null) { this.max_x_axis_value(options.max_x_axis_value); } 78 79 if (options.min_x_axis_value != null) { this.min_x_axis_value(options.min_x_axis_value); } 80 81 if (options.context_height != null) { this.context_height(options.context_height); } 82 83 if (options.auto_scale_y != null) { this.auto_scale_y(options.auto_scale_y); } 84 if (options.auto_scale_x != null) { this.auto_scale_x(options.auto_scale_x); } 85 86 if (options.auto_update_scale_y != null) { this.auto_update_scale_y(options.auto_update_scale_y); } 87 88 if (options.max_y_axis_value != null) { this.max_y_axis_value(options.max_y_axis_value); } 89 if (options.min_y_axis_value != null) { this.min_y_axis_value(options.min_y_axis_value); } 90 91 if (options.height != null) { this.height(options.height); } 92 93 if (options.width != null) { this.width(options.width); } 94 95 if (options.container) { this.container(options.container); } 96 97 if (options.vertical_padding != null) { this.vertical_padding(options.vertical_padding); } 98 99 if (options.horizontal_padding != null) { this.horizontal_padding(options.horizontal_padding); } 100 101 }; 102 103 vq.ChromaVis.prototype.draw = function(data) { 104 var that = this; 105 this._bl_data = new vq.models.ChromaVisData(data); 106 if (this._bl_data.isDataReady()) { 107 this._setOptionDefaults(that._bl_data); 108 this._render(); 109 } 110 }; 111 112 vq.ChromaVis.prototype._render = function() { 113 114 var that = this; 115 var dataObj = this._bl_data; 116 117 var x_label; 118 var left_margin = 55; 119 120 this.show_vals = false; 121 this.current_vals = {}; 122 that.mouse_x = null; 123 that.slaveRenderX = false; 124 that.slaveRenderY = false; 125 126 this.visibleWidth = (this.width() - 2 * this.horizontal_padding() - dataObj.legend_width) - left_margin; //40 is for y-axis label 127 this.visibleHeight = (this.height() - this.vertical_padding() * 2); 128 this.focus_height = this.visibleHeight - this.context_height(); 129 this.posX = pv.Scale.linear().range(0,that.visibleWidth); 130 this.min_x = pv.min(dataObj.data_array,function(a) { return pv.min(a[dataObj.data_contents_id],function(b) {return b[dataObj.x_column_id];});}); 131 this.max_x = pv.max(dataObj.data_array,function(a) { return pv.max(a[dataObj.data_contents_id],function(b) {return b[dataObj.x_column_id];});}); 132 133 this.max_y(pv.max(dataObj.data_array,function(a) { return pv.max(a[dataObj.data_contents_id],function(b) {return b[dataObj.y_column_id];});})); 134 135 var min_x = that.auto_scale_x() ? this.min_x : 136 that.min_x_axis_value(), 137 max_x = that.auto_scale_x() ? this.max_x : 138 that.max_x_axis_value(); 139 140 that.min_x_axis_value(min_x); 141 that.max_x_axis_value(max_x); 142 143 144 this.context_posX = pv.Scale.linear(that.min_x_axis_value(), that.max_x_axis_value()).range(0,that.visibleWidth); 145 that.window = {x:that.context_posX.range()[0],dx:(that.context_posX.range()[1] - that.context_posX.range()[0]) *.6}; 146 that.posX.domain(that.context_posX.invert(that.window.x),that.context_posX.invert(that.window.x + that.window.dx)); 147 that.focus_window = {x:0,dx:0}; 148 149 function update_vals() { 150 var index = -1; 151 that.show_vals = true; 152 that.mouse_x = that.posX.invert(tracks_panel.mouse().x); 153 dataObj.data_array.forEach(function(line) { 154 index = pv.search(line[dataObj.data_contents_id].map(function(point) { return point[dataObj.x_column_id];}),that.mouse_x); 155 index = index < 0 ? (-index -2) : index; 156 if (index < 0) { that.show_vals = false;} 157 that.current_vals[line[dataObj.data_label]]= index < 0 ? 0 : line[dataObj.data_contents_id][index][dataObj.y_column_id]; 158 }); 159 x_label.render(); 160 if (bubble) { 161 bubble.render(); 162 } 163 return legend; 164 } 165 166 function remove_vals() { that.show_vals = false; that.mouse_x = null; x_label.render(); return legend;} 167 168 169 var x = pv.Scale.linear(that.min_x_axis_value(),that.max_x_axis_value()) 170 .range(0,that.visibleWidth), 171 scale_height = this.focus_height - 4, 172 min_val = that.min_y_axis_value(), 173 max_val = that.auto_scale_y() ? this.max_y() : 174 this.max_y_axis_value(), 175 yScale = pv.Scale.linear(min_val,max_val ).range(0,scale_height); 176 dataObj.context_yScale = pv.Scale.linear(min_val,max_val ).range(0,that.context_height()-1); 177 178 this.max_y_axis_value(max_val); 179 this.min_y_axis_value(min_val); 180 181 if (dataObj.yaxis_scale_type != undefined && dataObj.yaxis_scale_type != null && 182 dataObj.yaxis_scale_type == 'log') { 183 min_val = min_val > 0 ? min_val : 1; 184 dataObj.base_value = dataObj.base_value > 0 185 ? dataObj.base_value : min_val; 186 yScale = pv.Scale.log(min_val,max_val ).range(0,scale_height).nice(); 187 dataObj.context_yScale = pv.Scale.log(min_val,max_val ).range(0,that.context_height()-1).nice(); 188 yScale.ticks = log_ticks(yScale.domain()); 189 } 190 191 dataObj.yScale = yScale; 192 193 var log_ticks = function(domain) { 194 var b = 10, 195 p = Math.log(b), 196 log = function(x) { return Math.log(x) / p; }, 197 pow = function(y) { return Math.pow(b, y); }; 198 n = domain[0] < 0, 199 i = Math.floor(n ? -log(-domain[0]) : log(domain[0])), 200 j = Math.ceil(n ? -log(-domain[1]) : log(domain[1])); 201 return function() { return pv.range(i,j+1,1).map(pow);};}; 202 203 var dd = vq.utils.VisUtils.clone(dataObj.data_array); 204 //array of array of timestamps 205 var contents = dd.map(function(a) { return a[dataObj.data_contents_id].map(function(b) { return b[dataObj.x_column_id];});}); 206 207 var init = function() { 208 209 var d1,d2; 210 if (!that.slaveRenderX) { 211 d1 = that.context_posX.invert(that.window.x), 212 d2 = that.context_posX.invert(that.window.x + that.window.dx), 213 that.posX.domain(d1, d2); 214 } 215 else { 216 d1 =that.posX.domain()[0]; 217 d2 =that.posX.domain()[1]; 218 that.window.x =that.context_posX(d1); 219 that.window.dx = that.context_posX(d2) - that.window.x; 220 } 221 //find the values just less than the minimum displayed x-axis value 222 //find the data line with the smallest of these values (how low to plot from) 223 var min_val = pv.min( 224 pv.blend( 225 contents.map(function(a) { 226 return pv.max( 227 a.filter(function(d) { 228 return d < d1;}));}))); 229 230 var max_val = pv.max( 231 pv.blend( 232 contents.map(function(a) { 233 return pv.min( 234 a.filter(function(d) { 235 return d > d2;}));}))); 236 237 var data = dd.map(function(line) { 238 var obj = {}; 239 obj[dataObj.data_label] = line[dataObj.data_label]; 240 obj[dataObj.data_contents_id] = 241 line[dataObj.data_contents_id].filter(function(d){ 242 return (d[dataObj.x_column_id] <= max_val && d[dataObj.x_column_id] >= min_val); 243 }); 244 return obj; 245 }); 246 if(!that.slaveRenderY) { 247 if (that.auto_update_scale_y()) { 248 var y_max_val = 249 pv.max(data,function(a) { return pv.max(a[dataObj.data_contents_id],function(b) {return b[dataObj.y_column_id];});}); 250 var domain = dataObj.yScale.domain(); 251 dataObj.yScale.domain(domain[0],y_max_val); 252 } else { 253 dataObj.yScale.domain(that.min_y_axis_value(),that.max_y_axis_value()); 254 } 255 } 256 257 return data; 258 }; 259 260 var vis = new pv.Panel() 261 .top(that.vertical_padding()) 262 .bottom(that.vertical_padding()) 263 .left(that.horizontal_padding()) 264 .right(that.horizontal_padding()) 265 .width(that.width()) 266 .height(that.height()) 267 .fillStyle(null) 268 .canvas(that.container()); 269 270 var wholePanel = vis.add(pv.Panel) 271 .left(0) 272 .top(0); 273 274 var drawPanel = wholePanel.add(pv.Panel) 275 .width(that.visibleWidth) 276 .left(left_margin); 277 this.drawPanel = drawPanel; 278 279 var y_axis_label=wholePanel.add(pv.Panel) 280 .top(that.focus_height/3) 281 .height(that.focus_height/3) 282 .left(0) 283 .width(10); 284 285 var focus = drawPanel.add(pv.Panel) 286 .top(0) 287 .left(0) 288 .height(that.focus_height); 289 var focus_click_panel = focus.add(pv.Panel); 290 291 var plot = focus.add(pv.Panel) 292 .bottom(0) 293 .overflow("hidden"); 294 295 focus.add(pv.Rule) 296 .left(0) 297 .add(pv.Rule) 298 .data(function() { return that.posX.ticks();} ) 299 .left(that.posX) 300 .strokeStyle("#888") 301 .events('none') 302 .anchor("bottom").add(pv.Label) 303 .text(that.posX.tickFormat); 304 305 x_label = focus.add(pv.Panel); 306 var x_rule = x_label.add(pv.Rule) 307 .visible(function() { return that.mouse_x;}) 308 .bottom(-10) 309 .height(10) 310 .strokeStyle("#888") 311 .events('none') 312 .left(function() { return that.posX(that.mouse_x);}); 313 x_rule.anchor("bottom").add(pv.Label) 314 .text(function() { return that.mouse_x.toFixed(2);}) 315 .font('4pt'); 316 317 if (dataObj.vertical_marker_array.length > 0) { 318 var marker_panel = focus.add(pv.Panel) 319 .overflow("hidden") 320 .data(dataObj.vertical_marker_array); 321 marker_panel.add(pv.Bar) 322 .lineWidth(2) 323 .left(function(marker) { return that.posX(marker.value);}) 324 .fillStyle('rgba(240,0,0,0.6)') 325 .strokeStyle('rgba(240,0,0,0.6)') 326 .width(1) 327 .anchor('left').add(pv.Label) 328 .font('10px sans-serif') 329 .textAngle(-Math.PI/2) 330 .textAlign('center') 331 .textBaseline('bottom') 332 .textStyle('black') 333 .text(function(marker){return marker.id;}); 334 } 335 336 var tracks_panel = plot.add(pv.Panel) 337 .data(function() { return init();}) 338 .left(0) 339 .width(that.visibleWidth); 340 341 342 var strokeStyle = dataObj.strokeStyle, 343 lineWidth = dataObj.lineWidth, 344 item = tracks_panel.add(pv.Line) 345 .data(function(d){ return d[dataObj.data_contents_id];}) 346 .left(function(c) { return that.posX(c[dataObj.x_column_id]);}) 347 .lineWidth(lineWidth) 348 .bottom(function(c){ return dataObj.yScale(c[dataObj.y_column_id]);}) 349 .strokeStyle(function() {return strokeStyle.call(this.parent);}); 350 351 352 if (dataObj.notifier != undefined){ 353 item.cursor('pointer') 354 .event('click',function(c,d){ dataObj.notifier(c,d); }); 355 } 356 357 if (dataObj.legend_width){ 358 item 359 .event('mousemove',update_vals) 360 .event('mouseout',function() { that.show_vals = false; that.mouse_x = null; return legend;}); 361 } 362 363 //only plot base_value ruler line if it falls in the current range of y-axis values 364 if (dataObj.yScale.domain()[0] <= dataObj.base_value && 365 dataObj.yScale.domain()[1] >= dataObj.base_value) { 366 focus.add(pv.Rule) 367 .bottom(function() { return dataObj.yScale(dataObj.base_value);}); 368 } else { // otherwise put the ruler along the bottom. 369 focus.add(pv.Rule) 370 .bottom(0); 371 } 372 focus.add(pv.Rule) 373 .data(function() { return dataObj.yScale.ticks(5);}) 374 .bottom(function(c) {return dataObj.yScale(c);}) 375 .strokeStyle('#222') 376 .width(10) 377 .left(0) 378 .anchor('left').add(pv.Label) 379 .font('4pt') 380 .text(function(c,d) {return dataObj.yScale.tickFormat(c);}); 381 382 y_axis_label.add(pv.Label) 383 .textAngle(-Math.PI/2) 384 .font('4pt') 385 .textAlign('center') 386 .textBaseline('middle') 387 .text(dataObj.y_axis_label); 388 389 var x_axis_label = drawPanel.add(pv.Panel) 390 .bottom(that.context_height()) 391 .height(15) 392 .left(0) 393 .width(that.visibleWidth) 394 .anchor('center').add(pv.Label) 395 .text(dataObj.x_axis_label) 396 .font('4pt') 397 .textBaseline('middle'); 398 399 400 /* Context panel (zoomed out). */ 401 var context = drawPanel.add(pv.Panel) 402 .bottom(0) 403 .width(that.visibleWidth) 404 .left(0) 405 .height(that.context_height()); 406 var context_panel = context.add(pv.Panel) 407 .bottom(0); 408 409 if (dataObj.vertical_marker_array.length > 0) { 410 var context_marker_panel = context_panel.add(pv.Panel) 411 .data(dataObj.vertical_marker_array); 412 context_marker_panel.add(pv.Bar) 413 .lineWidth(2) 414 .fillStyle('rgba(240,0,0,0.5)') 415 .left(function(marker) { return x(marker.value);}) 416 .fillStyle('rgba(240,0,0,0.5)') 417 .width(1) 418 419 } 420 421 var context_track = context_panel.add(pv.Panel) 422 .data(function(c) { return dataObj.data_array;}) 423 .overflow('hidden') 424 .left(0); 425 context_track.add(pv.Line) 426 .data(function(d){ return d[dataObj.data_contents_id];}) 427 .left(function(c) { return x(c[dataObj.x_column_id]);}) 428 .bottom(function(c){ return dataObj.context_yScale(c[dataObj.y_column_id]);}) 429 .lineWidth(.5) 430 .antialias(true) 431 .strokeStyle(function() {return strokeStyle.call(this.parent);}); 432 433 context.add(pv.Rule) 434 .left(0) 435 /* X-axis ticks. */ 436 .add(pv.Rule) 437 .data(that.context_posX.ticks()) 438 .left(that.context_posX) 439 .strokeStyle("#888") 440 .anchor("bottom").add(pv.Label) 441 .text(that.context_posX.tickFormat); 442 443 /* Y-axis ticks. */ 444 context.add(pv.Rule) 445 .bottom(0); 446 447 function render() { 448 drawPanel.render(); 449 } 450 451 function renderAndDispatch() { 452 if (that.window.dx < 2) { return; } 453 render(); 454 if(!dataObj.dispatch_events) { return; } 455 vq.events.Dispatcher.dispatch( 456 new vq.events.Event('chromavis_windowchange',that.uuid(),{ 457 pos: { 458 x:{min:that.context_posX.invert(that.window.x),max:that.context_posX.invert(that.window.dx +that.window.x) }, 459 y:{min: dataObj.yScale.domain()[0], max : dataObj.yScale.domain()[1]} } 460 })); 461 } 462 463 /* The selectable, draggable focus region. */ 464 context.add(pv.Panel) 465 .data(function() {return [that.window];}) 466 .cursor("crosshair") 467 .events("all") 468 .event("mousedown", pv.Behavior.select()) 469 .event("select", function() { 470 render(); 471 }) 472 .event("selectend", function() { 473 renderAndDispatch(); 474 }) 475 .add(pv.Bar) 476 .left(function(d) { return d.x;}) 477 .width(function(d) {return d.dx;}) 478 .fillStyle("rgba(255, 128, 128, .4)") 479 .cursor("move") 480 .event("mousedown", pv.Behavior.drag()) 481 .event("drag", function() { 482 render(); 483 }) 484 .event("dragend", function() { 485 renderAndDispatch(); 486 }); 487 488 /* The selectable, draggable focus region. */ 489 focus_click_panel 490 .data(function() { return [that.focus_window];}) 491 .cursor("crosshair") 492 .events("all") 493 .event("mousedown", pv.Behavior.select()) 494 .event("selectend", function() { 495 if (that.focus_window.dx < 2) { that.focus_window = {x:0,dx:0}; focus.render(); 496 context.render();return; } 497 that.window ={x: that.context_posX(that.posX.invert(that.focus_window.x)), 498 dx: that.context_posX(that.posX.invert(that.focus_window.dx)) - 499 that.context_posX(that.posX.invert(0))}; 500 if (dataObj.dispatch_events) { 501 vq.events.Dispatcher.dispatch( 502 new vq.events.Event('chromavis_windowchange',that.uuid(),{ 503 pos: { 504 x:{min:that.posX.invert(that.focus_window.x),max:that.posX.invert(that.focus_window.dx+that.focus_window.x)}, 505 y:{min: dataObj.yScale.domain()[0], max : dataObj.yScale.domain()[1]} } 506 507 })); 508 } 509 that.focus_window = {x:0,dx:0}; 510 drawPanel.render(); 511 }) 512 .add(pv.Bar) 513 .left(function(d) { return d.x;}) 514 .width(function(d) {return d.dx;}) 515 .fillStyle("rgba(128, 128, 255, .4)"); 516 517 var legend_height = 0; 518 519 if (dataObj.legend_width){ 520 legend_height = 12 * dataObj.data_array.length; 521 522 focus_click_panel 523 .event('mousemove',update_vals) 524 .event('mouseout',remove_vals); 525 526 var legend = drawPanel.add(pv.Panel) 527 .left(that.visibleWidth) 528 .width(dataObj.legend_width) 529 .top(10) 530 .height(legend_height); 531 var legend_item = legend.add(pv.Panel) 532 .data(dataObj.data_array) 533 .top(function(c) { return this.index * 12;}) 534 .height(10); 535 536 legend_item.add(pv.Bar) 537 .left(2) 538 .width(10) 539 .height(2) 540 .top(2) 541 .strokeStyle(function() {return strokeStyle.call(this.parent);}) 542 .anchor('right').add(pv.Label) 543 .text(function(c) { return c[dataObj.data_label] + (that.show_vals ? ' : ' + (that.current_vals[c[dataObj.data_label]]).toFixed(3) : '');}) 544 .textAlign('left') 545 .font("10px monospace"); 546 547 } 548 549 if (dataObj.data_array[0][dataObj.eri_id] != undefined && !isNaN(dataObj.data_array[0][dataObj.eri_id])) { 550 551 var new_vals = pv.normalize(dataObj.data_array, function(val){ return val.eri;}); 552 553 var norm_eri_ordered = dataObj.data_array.map(function(data,index) { return {eri:new_vals[index],label:data[dataObj.data_label]};}) 554 .sort(function(a,b) { 555 if(a.eri > b.eri) { return 1;} 556 else if(a.eri < b.eri) { return 1;} 557 else { return 0;}}); 558 559 function update_bubble() { 560 if(!that.show_vals) { return [50];} 561 var mean_square = pv.normalize(norm_eri_ordered.map(function(val) { return that.current_vals[val.label];})) 562 .reduce(function(prev,curr,index,arr){ 563 return prev + 564 (norm_eri_ordered[index][dataObj.eri_id] - curr) * 565 (norm_eri_ordered[index][dataObj.eri_id] - curr);},0); 566 return [Math.sqrt(mean_square) || 0]; 567 } 568 var bubble; 569 var eri_gauge_height = 0; 570 if(dataObj.eri_gauge) { 571 eri_gauge_height = 20; 572 var eri_gauge_width = 70; 573 var gauge_color_scale = pv.Scale.quantitative(0,dataObj.eri_bubble_max).range('#2f2','#f22'); 574 var gauge_xscale = pv.Scale.linear(0,dataObj.eri_bubble_max).range(0,eri_gauge_width); 575 var eri_gauge = drawPanel.add(pv.Panel) 576 .left(that.visibleWidth + 5) 577 .width(80) 578 .top(legend_height + 5) 579 .height(eri_gauge_height); 580 581 var gauge_line = eri_gauge.add(pv.Bar) 582 .bottom(9) 583 .width(eri_gauge_width) 584 .height(2) 585 .left(10) 586 .strokeStyle('#333') 587 .lineWidth(1); 588 eri_gauge.add(pv.Label) 589 .bottom(-10) 590 .left(3) 591 .text('Prediction Match'); 592 593 eri_gauge.add(pv.Rule) 594 .left(10) 595 .height(8) 596 .bottom(6) 597 .strokeStyle('#333') 598 .lineWidth(2); 599 600 eri_gauge.add(pv.Rule) 601 .left(eri_gauge_width+10) 602 .height(8) 603 .bottom(6) 604 .strokeStyle('#333') 605 .lineWidth(2); 606 607 var line_panel = eri_gauge.add(pv.Panel) 608 .bottom(10) 609 .width(eri_gauge_width) 610 .height(2) 611 .left(10) 612 .strokeStyle(null); 613 614 bubble = line_panel.add(pv.Dot) 615 .data(function() {return update_bubble();}) 616 .shape('circle') 617 .radius(4) 618 .strokeStyle('#333') 619 .lineWidth(1) 620 .fillStyle(function(c) { return gauge_color_scale(Math.min(dataObj.eri_bubble_max,c));}) 621 .bottom(0) 622 .left(function(c) { return gauge_xscale(Math.min(dataObj.eri_bubble_max,c));}); 623 } 624 625 var top_height = (legend_height + 15 + eri_gauge_height); 626 var height = that.focus_height - top_height; 627 function gaussian(val,eri) { 628 var exp = -1* Math.pow((val),2) / 2; 629 return eri * Math.exp(exp); 630 } 631 632 var line = pv.range(-1,1.01,0.01); 633 var x_axis = pv.Scale.linear(-1,1).range(0,80); 634 635 var expected = dataObj.data_array.map(function(line) { 636 return isNaN(line[dataObj.eri_id]) ? 0 : line[dataObj.eri_id]; }); 637 var max_eri = pv.max(expected); 638 var y_axis = pv.Scale.linear(0,max_eri).range(0,height -5); 639 640 var eri = drawPanel.add(pv.Panel) 641 .left(that.visibleWidth + 5) 642 .width(80) 643 .top(top_height) 644 .height(height); 645 646 eri.add(pv.Panel) 647 .data(expected) 648 .top(1) 649 .strokeStyle('black') 650 .lineWidth(1) 651 .add(pv.Line) 652 .data(line) 653 .bottom(function(c,d) { return y_axis(gaussian(c,d));}) 654 .left(x_axis) 655 .strokeStyle(function() { return strokeStyle.call(this.parent);}) 656 .lineWidth(dataObj.lineWidth); 657 } 658 659 vis.render(); 660 661 }; 662 663 664 vq.models.ChromaVisData = function(data) { 665 vq.models.VisData.call(this,data); 666 this._setDataModel(); 667 if (this.getDataType() == 'vq.models.ChromaVisData') { 668 this._build_data(this.getContents()); 669 } else { 670 console.warn('Unrecognized JSON object. Expected vq.models.ChromaVisData object.'); 671 } 672 }; 673 vq.models.ChromaVisData.prototype = pv.extend(vq.models.VisData); 674 675 vq.models.ChromaVisData.prototype._build_data = function(data) { 676 677 this._processData(data); 678 this.setDataReady(true); 679 }; 680 681 682 vq.models.ChromaVisData.prototype._setDataModel = function() { 683 this._dataModel = [ 684 {label: 'width', id: 'PLOT.width', cast : Number, defaultValue: 500}, 685 {label: 'height', id: 'PLOT.height', cast : Number, defaultValue: 500}, 686 {label : 'container', id:'PLOT.container', optional : true}, 687 {label: 'vertical_padding', id: 'PLOT.vertical_padding', cast : Number, defaultValue: 30}, 688 {label: 'horizontal_padding', id: 'PLOT.horizontal_padding',cast : Number, defaultValue: 30}, 689 {label: 'min_x_axis_value', id: 'PLOT.min_x_axis_value', cast : Number, defaultValue: 0}, 690 {label: 'max_x_axis_value', id: 'PLOT.max_x_axis_value',cast : Number, defaultValue: 100}, 691 {label: 'max_y_axis_value', id: 'PLOT.max_y_axis_value',cast : Number, defaultValue : 1}, 692 {label: 'min_y_axis_value', id: 'PLOT.min_y_axis_value',cast : Number, defaultValue : 0}, 693 {label: 'context_height', id: 'PLOT.context_height',cast : Number, defaultValue: 50}, 694 {label: 'legend_width', id: 'PLOT.legend_width',cast : Number, defaultValue : 0}, 695 {label: 'auto_scale_y', id: 'PLOT.auto_scale_y',cast : Boolean, defaultValue: false}, 696 {label: 'auto_update_scale_y', id: 'PLOT.auto_update_scale_y',cast : Boolean, defaultValue: false}, 697 {label : 'auto_scale_x', id: 'PLOT.auto_scale_x',cast : Boolean, defaultValue: false}, 698 {label : 'label', id: 'label', cast: String, defaultValue : '' }, 699 {label : 'type', id: 'type', cast: String, defaultValue : 'line' }, 700 {label : 'x_column_id' , id: 'x_column_id', cast : String, defaultValue : 'x'}, 701 {label : 'y_column_id' , id: 'y_column_id', cast : String, defaultValue : 'y'}, 702 {label : 'eri_id' , id: 'eri_id', cast : String, defaultValue : 'eri'}, 703 {label : 'eri_gauge' , id: 'PLOT.eri_gauge', cast : Boolean, defaultValue : false}, 704 {label : 'y_axis_label' , id: 'y_axis_label', cast : String, defaultValue : 'Intensity'}, 705 {label : 'x_axis_label' , id: 'x_axis_label', cast : String, defaultValue : 'Time(ms)'}, 706 {label : 'strokeStyle', id: 'stroke_style', cast: vq.utils.VisUtils.wrapProperty, defaultValue : pv.Colors.category10() }, 707 {label : 'lineWidth', id: 'line_width', cast: vq.utils.VisUtils.wrapProperty, defaultValue : vq.utils.VisUtils.wrapProperty(1) }, 708 {label : 'base_value', id: 'base_value', cast: Number, defaultValue : 0 }, 709 {label : 'yaxis_scale_type', id: 'yaxis_scale_type', cast: String, defaultValue : 'linear' }, 710 {label : 'eri_bubble_max', id:'eri_bubble_max', cast : Number, defaultValue : 0.1}, 711 {label : 'notifier', id: 'notifier', cast: Function, optional : true }, 712 {label : 'tooltipItems', id: 'tooltip_items', defaultValue : 713 {X : 'x' , Value : 'y'} }, 714 {label : 'dispatch_events', id:'dispatch_events',cast: Boolean, defaultValue: true}, 715 {label : 'data_array', id: 'data_array', defaultValue : [] }, 716 {label : 'vertical_marker_array', id:'vertical_marker_array', cast: Object, defaulValue: [] }, 717 {label : 'data_label', id: 'data_label', defaultValue : 'label'}, 718 {label : 'data_contents_id', id : 'data_contents_id', defaultValue : 'data'} 719 ]; 720 }; 721 722