Mercurial > repos > immport-devteam > flow_overview
comparison js/parallelCoordinates.js @ 1:b5453d07f740 draft default tip
"planemo upload for repository https://github.com/ImmPortDB/immport-galaxy-tools/tree/master/flowtools/flow_overview commit 65373effef15809f3db0e5f9603ef808f4110aa3"
author | azomics |
---|---|
date | Wed, 29 Jul 2020 17:03:53 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8283ff163ba6 | 1:b5453d07f740 |
---|---|
1 // Copyright (c) 2016 Northrop Grumman. | |
2 // All rights reserved. | |
3 /* | |
4 * Initialize variables for parallelCoordinates display | |
5 */ | |
6 var pCoordApp = pCoordApp || {}; | |
7 pCoordApp.allPopulations = []; | |
8 pCoordApp.selectedPopulations = []; | |
9 pCoordApp.origData; | |
10 pCoordApp.flowData; | |
11 pCoordApp.headers = []; | |
12 pCoordApp.foreground; | |
13 pCoordApp.background; | |
14 pCoordApp.populations = []; | |
15 pCoordApp.allLines; | |
16 pCoordApp.lines = []; | |
17 pCoordApp.selectedLines = []; | |
18 | |
19 var displayAll = function() { | |
20 displayParallelPlot(); | |
21 } | |
22 /* | |
23 * Display the Population Legend | |
24 */ | |
25 var displayPopTable = function() { | |
26 $('#popTable tbody').empty(); | |
27 pCoordApp.origData.map(function(d,index) { | |
28 $('#popTable tbody') | |
29 .append('<tr><td align="center"><input type="checkbox" ' | |
30 + 'id="pop' + d.Population + '" ' | |
31 + 'checked class="popSelect" value=' + index + '/></td>' | |
32 + '<td title="' + newNames[d.Population] + '">' | |
33 + newNames[d.Population] | |
34 + '</td><td><span style="background-color:' | |
35 + color_palette[0][index + 1][0] | |
36 + '"> </span></td>' | |
37 + '<td>' + d.Percentage + '</td></tr>'); | |
38 }); | |
39 | |
40 $('#popSelectAll').click(function() { | |
41 var checkAll = $("#popSelectAll").prop('checked'); | |
42 if (checkAll) { | |
43 $(".popSelect").prop("checked", true); | |
44 for (var i = 0; i < pCoordApp.allLines; i ++){ | |
45 pCoordApp.selectedLines.push(i); | |
46 pCoordApp.lines.push(i); | |
47 } | |
48 } else { | |
49 $(".popSelect").prop("checked", false); | |
50 pCoordApp.selectedLines = []; | |
51 pCoordApp.lines = []; | |
52 } | |
53 | |
54 pCoordApp.selectedPopulations = []; | |
55 $('.popSelect').each(function() { | |
56 if (this.checked) { | |
57 pCoordApp.selectedPopulations.push(parseInt(this.value)); | |
58 } | |
59 }); | |
60 displayTableGrid(); | |
61 if (checkAll) { | |
62 displayParallelPlot(); | |
63 } else { | |
64 updateParallelForeground(); | |
65 } | |
66 }); | |
67 | |
68 $('.popSelect').click(function() { | |
69 if ($('.popSelect').length == $(".popSelect:checked").length) { | |
70 $('#popSelectAll').prop("checked",true); | |
71 } else { | |
72 $('#popSelectAll').prop("checked",false); | |
73 } | |
74 | |
75 pCoordApp.selectedPopulations = []; | |
76 $('.popSelect').each(function() { | |
77 if (this.checked) { | |
78 pCoordApp.selectedPopulations.push(parseInt(this.value)); | |
79 } | |
80 }); | |
81 | |
82 pCoordApp.selectedLines = []; | |
83 pCoordApp.lines = []; | |
84 | |
85 pCoordApp.origData.forEach(function(d,idx){ | |
86 if ($.inArray(pCoordApp.populations.indexOf(d.Population), pCoordApp.selectedPopulations) > -1) { | |
87 pCoordApp.selectedLines.push(idx); | |
88 pCoordApp.lines.push(idx); | |
89 } | |
90 }); | |
91 | |
92 displayTableGrid(); | |
93 updateParallelForeground(); | |
94 }); | |
95 updatePopTable(); | |
96 }; | |
97 | |
98 var updatePopTable = function() { | |
99 $('.popSelect').each(function() { | |
100 var pop = parseInt(this.value), | |
101 selectedPops = pCoordApp.origData.map(function(d){ | |
102 if ($.inArray(d.idx, pCoordApp.selectedLines) > -1){ | |
103 return pCoordApp.populations.indexOf(d.Population); | |
104 } | |
105 }); | |
106 if ($.inArray(pop,selectedPops) > -1) { | |
107 this.checked = true; | |
108 } else { | |
109 this.checked = false; | |
110 } | |
111 }); | |
112 }; | |
113 | |
114 /* | |
115 * Display the table under the graph | |
116 */ | |
117 var displayTableGrid = function() { | |
118 var updatedData = [], | |
119 displayData = [], | |
120 colNames = [], | |
121 pctargets = [], | |
122 colTable = [], | |
123 tableHTML = [], | |
124 textCol = [], | |
125 colOrder = [], | |
126 targetCol = 0; | |
127 | |
128 $("#tableDiv").empty(); | |
129 updatedData = $.extend(true, [], tableContent); | |
130 updatedData.forEach(function(d, idx){d.idx = idx}); | |
131 displayData = updatedData.filter(function(d, index) { | |
132 if ($.inArray(index,pCoordApp.selectedLines) > -1) { | |
133 return d; | |
134 } | |
135 }); | |
136 | |
137 targetCol = pCoordApp.headers.length - 2; | |
138 pCoordApp.headers.forEach(function(d,i){ | |
139 colTable.push("<th>" + d + "</th>"); | |
140 colNames.push({"data":d}); | |
141 if (i < targetCol){ | |
142 pctargets.push(i); | |
143 } | |
144 }); | |
145 textCol = [targetCol, targetCol + 1]; | |
146 colOrder = textCol.concat(pctargets); | |
147 tableHTML = [ | |
148 '<table id="pcTable" class="pctable display compact" cellspacing="0" width="100%">', | |
149 '<thead>', | |
150 '<tr>', | |
151 colTable.join("\n"), | |
152 '</tr>', | |
153 '</thead>', | |
154 '</table>', | |
155 ]; | |
156 | |
157 $('#tableDiv').html(tableHTML.join("\n")); | |
158 var pcTable = $('#pcTable').DataTable({ | |
159 columns: colNames, | |
160 data: displayData, | |
161 order: [[ targetCol, "asc" ]], | |
162 pageLength: 10, | |
163 //paging: false, | |
164 scrollY: 250, | |
165 scrollCollapse: true, | |
166 scrollX: true, | |
167 dom: '<"top"B>t<"bottom"lip><"clear">', | |
168 columnDefs: [{ | |
169 targets: pctargets, | |
170 className: "dt-body-right", | |
171 }, { | |
172 targets: [targetCol, targetCol+1], | |
173 className: "dt-body-center" | |
174 }], | |
175 buttons: [ | |
176 'copy', 'pdfHtml5','csvHtml5', 'colvis' | |
177 ], | |
178 colReorder: { | |
179 order:colOrder | |
180 }, | |
181 select: true | |
182 }); | |
183 | |
184 $('#pcTable').on('mouseover', 'tr', function() { | |
185 var data = pcTable.row(this).data(); | |
186 if (data != undefined) { | |
187 var line = data.idx; | |
188 pCoordApp.selectedLines = [ line ]; | |
189 updateParallelForeground(); | |
190 } | |
191 }); | |
192 $('#pcTable').on('mouseleave', 'tr', function() { | |
193 pCoordApp.selectedLines = []; | |
194 for (var i = 0, j = pCoordApp.lines.length; i < j; i++) { | |
195 pCoordApp.selectedLines.push(pCoordApp.lines[i]); | |
196 } | |
197 updateParallelForeground(); | |
198 }); | |
199 }; | |
200 | |
201 /* | |
202 * Display The Main Plot | |
203 */ | |
204 var displayParallelPlot = function() { | |
205 var margin = {top: 30, right: 10, bottom: 10, left: 10}, | |
206 h = $("#chartDiv").height()/1.5, | |
207 w = $("#plotDiv").width(), | |
208 width = w - margin.left - margin.right, | |
209 height = h - margin.top - margin.bottom, | |
210 dragging = {}, | |
211 y = {}; | |
212 | |
213 $("#plotDiv").empty(); | |
214 $("#plotDiv").height(h); | |
215 var svg = d3.select("#plotDiv").append("svg") | |
216 .attr("width", width + margin.left + margin.right) | |
217 .attr("height", height + margin.top + margin.bottom) | |
218 .append("g") | |
219 .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
220 | |
221 // Y axis label | |
222 svg.append("text") | |
223 .attr("class", "ylabel") | |
224 .attr("transform", "rotate(-90)") | |
225 .attr("y", 0 - margin.left) | |
226 .attr("x", 0 - (height / 2)) | |
227 .attr("dy", "1em") | |
228 .style("text-anchor", "middle") | |
229 .text("MFI"); | |
230 | |
231 var x = d3.scale.ordinal().rangePoints([0, width], 1); | |
232 | |
233 // Use this to scale line width to percentage population | |
234 var pd = d3.extent(pCoordApp.origData, function(p) { | |
235 return +p['Percentage']; | |
236 }); | |
237 var popScale = d3.scale.linear().range([1,5]).domain(pd); | |
238 | |
239 var line = d3.svg.line(); | |
240 var axis = d3.svg.axis().orient("left").ticks(8); | |
241 | |
242 var dimensions = d3.keys(pCoordApp.flowData[0]).filter(function(d) { | |
243 return (y[d] = d3.scale.linear() | |
244 .domain(d3.extent(pCoordApp.flowData,function(p) { return +p[d]; })) | |
245 .range([height, 0])); | |
246 }); | |
247 x.domain(dimensions); | |
248 | |
249 function path(d) { | |
250 return line(dimensions.map(function(p) { | |
251 return [x(p), y[p](d[p])]; | |
252 })); | |
253 } | |
254 function position(d) { | |
255 var v = dragging[d]; | |
256 return v == null ? x(d) : v; | |
257 } | |
258 function transition(g) { | |
259 return g.transition().duration(500); | |
260 } | |
261 function brush() { | |
262 var actives = dimensions.filter(function(p) { | |
263 return !y[p].brush.empty(); | |
264 }); | |
265 var extents = actives.map(function(p) { | |
266 return y[p].brush.extent(); | |
267 }); | |
268 var indices = pCoordApp.origData.filter(function(d) { | |
269 var line = d.idx; | |
270 var tf = actives.every(function(p,i) { | |
271 return extents[i][0] <= pCoordApp.flowData[line][p] && | |
272 pCoordApp.flowData[line][p] <= extents[i][1]; | |
273 }); | |
274 if (tf) { | |
275 return line.toString(); | |
276 } | |
277 }); | |
278 pCoordApp.selectedLines = indices.map(function(d) { | |
279 return d.idx; | |
280 }); | |
281 pCoordApp.lines = indices.map(function(d) { | |
282 return d.idx; | |
283 }); | |
284 | |
285 updateParallelForeground(); | |
286 updatePopTable(); | |
287 displayTableGrid(); | |
288 }; | |
289 | |
290 // Display paths in light gray color, to use as reference | |
291 pCoordApp.background = svg.append("g") | |
292 .attr("class", "background") | |
293 .selectAll("path") | |
294 .data(pCoordApp.flowData) | |
295 .enter().append("path") | |
296 .attr("d", path); | |
297 | |
298 // Add foreground lines for focus, color by population. | |
299 pCoordApp.foreground = svg.append("g") | |
300 .attr("class", "foreground") | |
301 .selectAll("path") | |
302 .data(pCoordApp.origData) | |
303 .enter().append("path") | |
304 .attr("d", path) | |
305 .attr("stroke",function(d){ | |
306 var pop = pCoordApp.populations.indexOf(d.Population) + 1; | |
307 return color_palette[0][pop][0]; | |
308 }) | |
309 //.attr("stroke-width", 2); | |
310 // Use this if you want to scale the lines based on | |
311 // population percentage | |
312 .attr("stroke-width", function(d) { | |
313 var pop = pCoordApp.populations.indexOf(d.Population); | |
314 var w = popScale(pCoordApp.origData[pop]['Percentage']); | |
315 w = parseInt(w); | |
316 return w; | |
317 }); | |
318 | |
319 // Add a group element for each dimension. | |
320 var g = svg.selectAll(".dimension") | |
321 .data(dimensions) | |
322 .enter().append("g") | |
323 .attr("class", "dimension") | |
324 .attr("transform", function(d) { return "translate(" + x(d) + ")"; }) | |
325 .call(d3.behavior.drag() | |
326 .origin(function(d) { return {x: x(d)}; }) | |
327 .on("dragstart", function(d) { | |
328 dragging[d] = x(d); | |
329 pCoordApp.background.attr("visibility", "hidden"); | |
330 }) | |
331 .on("drag", function(d) { | |
332 dragging[d] = Math.min(width, Math.max(0, d3.event.x)); | |
333 pCoordApp.foreground.attr("d", path); | |
334 dimensions.sort(function(a, b) { | |
335 return position(a) - position(b); | |
336 }); | |
337 x.domain(dimensions); | |
338 g.attr("transform", function(d) { | |
339 return "translate(" + position(d) + ")"; | |
340 }); | |
341 }) | |
342 .on("dragend", function(d) { | |
343 delete dragging[d]; | |
344 transition(d3.select(this)) | |
345 .attr("transform", "translate(" + x(d) + ")"); | |
346 transition(pCoordApp.foreground) | |
347 .attr("d", path); | |
348 pCoordApp.background.attr("d", path) | |
349 .transition() | |
350 .delay(500) | |
351 .duration(0) | |
352 .attr("visibility", null); | |
353 })); | |
354 | |
355 // Add an axis and title. | |
356 g.append("g") | |
357 .attr("class", "axis") | |
358 .each(function(d) { | |
359 d3.select(this).call(axis.scale(y[d])); | |
360 }); | |
361 g.append("g") | |
362 .attr("class", "xlabel") | |
363 .append("text") | |
364 .style("text-anchor", "middle") | |
365 .attr("y", -9) | |
366 .text(function(d) { return d; }); | |
367 | |
368 // Add and store a brush for each axis. | |
369 g.append("g") | |
370 .attr("class", "brush") | |
371 .each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brush", brush)); }) | |
372 .selectAll("rect") | |
373 .attr("x", -8) | |
374 .attr("width", 16); | |
375 | |
376 // Control line opacity. | |
377 $('#pcline_opacity').on('change', (function() { | |
378 var val = $(this).val(); | |
379 $('#plotDiv .foreground path').css('stroke-opacity', val.toString()); | |
380 $('#pcopacity').html((Math.round(val*10000)/100) + "%"); | |
381 })); | |
382 }; | |
383 | |
384 var updateParallelForeground = function() { | |
385 pCoordApp.foreground[0].map(function(d) { | |
386 var ln = parseInt(d['__data__']['idx']); | |
387 if ($.inArray(ln, pCoordApp.selectedLines) < 0){ | |
388 d.style.display = "none"; | |
389 } else { | |
390 d.style.display = null; | |
391 } | |
392 }); | |
393 }; | |
394 | |
395 /* | |
396 * Retrieve the data, then call display functions | |
397 */ | |
398 var displayParallelCoordinates = function() { | |
399 pCoordApp.origData = $.extend(true,[], tableContent); | |
400 pCoordApp.headers = Object.keys(pCoordApp.origData[0]); | |
401 pCoordApp.origData.forEach(function(d,idx) { | |
402 d.idx = idx; | |
403 pCoordApp.selectedLines.push(idx); | |
404 pCoordApp.lines.push(idx); | |
405 if (!pCoordApp.populations.includes(d.Population)){ | |
406 pCoordApp.populations.push(d.Population); | |
407 } | |
408 }); | |
409 /* | |
410 * For the plot use only the MFI information | |
411 * for each populations. Store in flowData | |
412 */ | |
413 pCoordApp.flowData = $.extend(true,[],tableContent); | |
414 pCoordApp.flowData.forEach(function(d, idx) { | |
415 delete d['Population']; | |
416 delete d['Count']; | |
417 delete d['Percentage']; | |
418 delete d.Comment; | |
419 pCoordApp.allPopulations.push(idx); | |
420 pCoordApp.selectedPopulations.push(idx); | |
421 pCoordApp.selectedLines.push(idx); | |
422 pCoordApp.lines.push(idx); | |
423 }); | |
424 | |
425 pCoordApp.allLines = pCoordApp.flowData.length; | |
426 displayPopTable(); | |
427 displayTableGrid(); | |
428 displayParallelPlot(); | |
429 | |
430 $("#resetPCoordDisplay").on("click",function() { | |
431 for (var i = 0; i < pCoordApp.allLines; i++) { | |
432 pCoordApp.allPopulations.push(i); | |
433 pCoordApp.selectedPopulations.push(i); | |
434 pCoordApp.selectedLines.push(i); | |
435 pCoordApp.lines.push(i); | |
436 } | |
437 $("#popSelectAll").prop('checked',true); | |
438 $(".popSelect").prop("checked",true); | |
439 | |
440 var opcty = ".8"; | |
441 $('#plotDiv .foreground path').css('stroke-opacity', opcty); | |
442 $('#pcopacity').html("80%"); | |
443 $('#pcline_opacity').val(0.8); | |
444 | |
445 displayPopTable(); | |
446 displayTableGrid(); | |
447 displayParallelPlot(); | |
448 }); | |
449 | |
450 $(window).on('resize',function() { | |
451 waitForFinalEvent(function() { | |
452 displayAll(); | |
453 }, 500, "resizeParallelCoordinates"); | |
454 }); | |
455 } |