parallelcoordinates.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. Shiny.addCustomMessageHandler("parallelcoordinates_values", function (message) {
  2. //TRATAMENTO INICIAL DOS DADOS - TRANSPOSIÇÃO
  3. var dataset = message;
  4. var numero_dados = dataset.Acidentes.length;
  5. var dado = { Acidentes: null, Sexo: null, Hora: null };
  6. var vetorDados = [];
  7. var traits = ['Acidentes', 'Sexo', 'Hora', 'Media de Idade'];
  8. var o;
  9. for (o = 0; o < numero_dados; o++) {
  10. traits.forEach(function (string) {
  11. dado[string] = dataset[string][o];
  12. });
  13. vetorDados.push(dado);
  14. dado = {};
  15. }
  16. var parcoordstable = d3.select("#parallelcoordinates_table table");
  17. var checkboxes = d3.select("#parallelcoordinates_area")
  18. .append("div")
  19. .attr("id", "parallel-coordinates-switch");
  20. function toggleAxis(checkBox, trait) {
  21. if (checkBox.checked == true) {
  22. if (!traits.includes(trait))
  23. traits.push(trait);
  24. }
  25. if (checkBox.checked == false) {
  26. var i = traits.indexOf(trait);
  27. traits.splice(i, 1);
  28. }
  29. d3.select("#parallelcoordinates_area svg").remove();
  30. loadChart();
  31. }
  32. traits.forEach(function (trait) {
  33. checkboxes.append("input")
  34. .attr("type", "checkbox")
  35. .attr("id", trait)
  36. .attr("value", trait)
  37. .attr("checked", true)
  38. .on("click", function () {
  39. toggleAxis(this, trait);
  40. });
  41. checkboxes.append("text")
  42. .text(trait);
  43. });
  44. function loadChart() {
  45. dragging = {};
  46. var background;
  47. var m = [50, 80, 50, 100],
  48. w = 500 - m[1] - m[3],
  49. h = 400 - m[0] - m[2];
  50. var line = d3.line(),
  51. axis = d3.axisLeft(),
  52. foreground;
  53. var parcoords = d3.select("#parallelcoordinates_area").append("svg")
  54. .attr("width", w + m[1] + m[3])
  55. .attr("height", h + m[0] + m[2])
  56. .append("g")
  57. .attr("transform", "translate(" + m[3] +
  58. "," + m[0] + ")");
  59. // Create a scale and brush for each trait
  60. var x = d3.scalePoint().domain(traits).range([0, w]),
  61. y = {};
  62. traits.forEach(function (col) {
  63. vetorDados.forEach(function (p) {
  64. p[col] = +p[col];
  65. });
  66. y[col] = d3.scaleLinear()
  67. .domain(d3.extent(vetorDados, function (p) {
  68. return p[col];
  69. }))
  70. .range([h, 0]);
  71. //CREATE BRUSH
  72. y[col].brush = d3.brushY()
  73. .extent([[-7, y[col].range()[1]],
  74. [7, y[col].range()[0]]
  75. ])
  76. .on("start", brushstart)
  77. .on("brush", brushView)
  78. .on("end", brush);
  79. });
  80. //APPEND BACKGROUND
  81. background = parcoords.append("g")
  82. .attr("class", "background")
  83. .selectAll("path")
  84. .data(vetorDados)
  85. .enter().append("path")
  86. .attr("d", path);
  87. // ADD FOREGROUND LINES
  88. foreground = parcoords.append("g")
  89. .attr("class", "foreground")
  90. .selectAll("path")
  91. .data(vetorDados)
  92. .enter().append("path")
  93. .attr("d", path);
  94. // Add a group element for each trait.
  95. var g = parcoords.selectAll(".trait")
  96. .data(traits)
  97. .enter()
  98. .append("svg:g")
  99. .attr("class", "trait")
  100. .attr("transform", function (d) {
  101. return "translate(" + x(d) + ")";
  102. })
  103. .call(d3.drag()
  104. .subject(function (d) {
  105. return { x: x(d) };
  106. })
  107. .on("start", function (d) {
  108. dragging[d] = x(d);
  109. background.attr("visibility", "hidden");
  110. })
  111. .on("drag", function (d) {
  112. //+10 e -10 para mudar com o primeiro e o ultimo
  113. dragging[d] = Math.min(w + 10, Math.max(-10, d3.event.x));
  114. foreground.attr("d", path);
  115. traits.sort(function (a, b) {
  116. return position(a) - position(b);
  117. });
  118. x.domain(traits);
  119. g.attr("transform", function (d) {
  120. return "translate(" + position(d) + ")";
  121. });
  122. })
  123. .on("end", function (d) {
  124. delete dragging[d];
  125. transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")");
  126. transition(foreground).attr("d", path);
  127. background
  128. .attr("d", path)
  129. .transition()
  130. .delay(500)
  131. .duration(0)
  132. .attr("visibility", null);
  133. })
  134. );
  135. //BACKGROUND GRADIENT do eixo Sexo
  136. var defs = parcoords.append("defs");
  137. var gradient = defs.append("linearGradient")
  138. .attr("id", "svgGradient")
  139. .attr("x1", "50%")
  140. .attr("x2", "100%")
  141. .attr("y1", "50%")
  142. .attr("y2", "100%");
  143. gradient.append("stop")
  144. .attr('class', 'start')
  145. .attr("offset", "0%")
  146. .attr("stop-color", "blue")
  147. .attr("stop-opacity", 1);
  148. gradient.append("stop")
  149. .attr('class', 'end')
  150. .attr("offset", "100%")
  151. .attr("stop-color", "red")
  152. .attr("stop-opacity", 1);
  153. //Eixos
  154. g.append("svg:g")
  155. .attr("class", "axis")
  156. .each(function (col) {
  157. // Para remover os nomes das cidades
  158. if (col == "municipio") {
  159. d3.select(this)
  160. .call(d3.axisLeft(y[col]))
  161. .selectAll("text").remove();
  162. }
  163. if (col == "Sexo") {
  164. d3.select(this)
  165. .attr("class", "eixoSexo")
  166. .call(d3.axisLeft(y[col]))
  167. .selectAll("text").remove();
  168. d3.select(this)
  169. .call(d3.axisLeft(y[col])
  170. .ticks(3));
  171. d3.select(this)
  172. .append("svg:text").text("M")
  173. .attr("x", -9)
  174. .attr("y", 10);
  175. d3.select(this)
  176. .append("svg:text").text("F")
  177. .attr("x", -9)
  178. .attr("y", h + 2);
  179. }
  180. else if (col == "Hora") {
  181. d3.select(this).call(d3.axisLeft(y[col]).ticks(18));
  182. }
  183. else if (col == "Causador") {
  184. // ALT
  185. d3.select(this)
  186. .call(d3.axisLeft(y[col]))
  187. .selectAll("text")
  188. ._groups[0].forEach(function (p) {
  189. p.innerHTML = p.innerHTML.split(" ")[0];
  190. });
  191. }
  192. else {
  193. d3.select(this).call(d3.axisLeft(y[col]));
  194. }
  195. })
  196. // Titulos dos eixos
  197. .append("svg:text")
  198. .attr("text-anchor", "middle")
  199. .attr("y", -15)
  200. .text(function (col) {
  201. return col;
  202. });
  203. // Add a brush for each axis.
  204. g.append("svg:g")
  205. .attr("class", "brush")
  206. .each(function (d) {
  207. d3.select(this).call(y[d].brush);
  208. })
  209. .selectAll("rect")
  210. .attr("x", -8)
  211. .attr("width", 16);
  212. function position(d) {
  213. var v = dragging[d];
  214. return v == null ? x(d) : v;
  215. }
  216. function transition(g) {
  217. return g.transition().duration(500);
  218. }
  219. // Returns the path for a given data point.
  220. function path(d) {
  221. return line(traits.map(function (p) {
  222. return [position(p), y[p](d[p])];
  223. }));
  224. }
  225. // BRUSH FUNCTIONS
  226. function brushstart() {
  227. d3.event.sourceEvent.stopPropagation();
  228. }
  229. function brushView() {
  230. var actives = [];
  231. //filter brushed extents
  232. parcoords.selectAll(".brush")
  233. .filter(function (d) {
  234. return d3.brushSelection(this);
  235. })
  236. .each(function (d) {
  237. actives.push({
  238. dimension: d,
  239. extent: d3.brushSelection(this)
  240. });
  241. dim = actives[0].dimension;
  242. });
  243. //set un-brushed foreground line disappear
  244. foreground.classed("fade", function (d, i) {
  245. return !actives.every(function (active) {
  246. var dim = active.dimension;
  247. return active.extent[0] <= y[dim](d[dim]) && y[dim](d[dim]) <= active.extent[1];
  248. });
  249. });
  250. }
  251. function brush() {
  252. var actives = [];
  253. //filter brushed extents
  254. parcoords.selectAll(".brush")
  255. .filter(function (d) {
  256. return d3.brushSelection(this);
  257. })
  258. .each(function (d) {
  259. actives.push({
  260. dimension: d,
  261. extent: d3.brushSelection(this)
  262. });
  263. var selected = vetorDados.filter(function (d) {
  264. return actives.every(function (active) {
  265. var dim = active.dimension;
  266. return active.extent[0] <= y[dim](d[dim]) && y[dim](d[dim]) <= active.extent[1];
  267. });
  268. });
  269. hideTableColNames();
  270. d3.selectAll(".row_data").remove();
  271. showTableColNames();
  272. selected.forEach(function (d) {
  273. var row = parcoordstable.append("tr")
  274. .attr("class", "row_data");
  275. traits.forEach(
  276. function (string) {
  277. row.append("td")
  278. .text(d[string]);
  279. }
  280. );
  281. });
  282. });
  283. foreground.classed("fade", function (d, i) {
  284. return !actives.every(function (active) {
  285. var dim = active.dimension;
  286. return active.extent[0] <= y[dim](d[dim]) && y[dim](d[dim]) <= active.extent[1];
  287. });
  288. });
  289. }
  290. function hideTableColNames() {
  291. table.style("visibility", "hidden");
  292. }
  293. function showTableColNames() {
  294. table.style("visibility", "visible");
  295. }
  296. }
  297. // IMPORTANTE
  298. loadChart();
  299. });