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 + '">&nbsp;&nbsp;&nbsp;</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 }